promigence 0.1.0-beta.12
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/NOTICE +14 -0
- package/README.md +88 -0
- package/dist/account.js +850 -0
- package/dist/agent.js +374 -0
- package/dist/argv.js +159 -0
- package/dist/bin.js +332 -0
- package/dist/bundle.js +133 -0
- package/dist/capacity.js +69 -0
- package/dist/commands.d.ts +110 -0
- package/dist/commands.js +2675 -0
- package/dist/connectreq.js +125 -0
- package/dist/credfile.js +188 -0
- package/dist/credits.js +197 -0
- package/dist/devcontainer.d.ts +99 -0
- package/dist/devcontainer.js +744 -0
- package/dist/device.js +129 -0
- package/dist/dirsnap.js +378 -0
- package/dist/errfix.js +262 -0
- package/dist/generated.d.ts +35 -0
- package/dist/generated.js +307 -0
- package/dist/github.js +307 -0
- package/dist/gitlab.js +210 -0
- package/dist/guide.d.ts +19 -0
- package/dist/guide.js +366 -0
- package/dist/handlers.js +511 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +7 -0
- package/dist/init.d.ts +40 -0
- package/dist/init.js +352 -0
- package/dist/install.d.ts +23 -0
- package/dist/install.js +127 -0
- package/dist/io.d.ts +37 -0
- package/dist/io.js +318 -0
- package/dist/live.js +469 -0
- package/dist/login.js +1063 -0
- package/dist/mcp.js +889 -0
- package/dist/money.js +5 -0
- package/dist/orgs.js +475 -0
- package/dist/pricing.d.ts +52 -0
- package/dist/pricing.js +181 -0
- package/dist/report.js +132 -0
- package/dist/routes.js +135 -0
- package/dist/runners-github.js +257 -0
- package/dist/runners-gitlab.js +125 -0
- package/dist/runners-spec.js +137 -0
- package/dist/runners.js +1458 -0
- package/dist/sdk/blake3.d.ts +10 -0
- package/dist/sdk/blake3.js +111 -0
- package/dist/sdk/bundle.d.ts +96 -0
- package/dist/sdk/bundle.js +227 -0
- package/dist/sdk/ca-guard.js +166 -0
- package/dist/sdk/caller.d.ts +73 -0
- package/dist/sdk/caller.js +47 -0
- package/dist/sdk/client.d.ts +3015 -0
- package/dist/sdk/client.js +2583 -0
- package/dist/sdk/command-errors.d.ts +41 -0
- package/dist/sdk/command-errors.js +36 -0
- package/dist/sdk/context.d.ts +119 -0
- package/dist/sdk/context.js +588 -0
- package/dist/sdk/core.d.ts +285 -0
- package/dist/sdk/core.js +266 -0
- package/dist/sdk/credstore.d.ts +90 -0
- package/dist/sdk/credstore.js +206 -0
- package/dist/sdk/dispatcher.js +86 -0
- package/dist/sdk/github.d.ts +158 -0
- package/dist/sdk/github.js +78 -0
- package/dist/sdk/gitlab.d.ts +104 -0
- package/dist/sdk/gitlab.js +20 -0
- package/dist/sdk/handles.d.ts +82 -0
- package/dist/sdk/handles.js +135 -0
- package/dist/sdk/hint.js +7 -0
- package/dist/sdk/http2.js +1921 -0
- package/dist/sdk/index.d.ts +34 -0
- package/dist/sdk/index.js +15 -0
- package/dist/sdk/keyed.gen.js +7 -0
- package/dist/sdk/models.gen.d.ts +6162 -0
- package/dist/sdk/models.gen.js +1 -0
- package/dist/sdk/proxy.js +249 -0
- package/dist/sdk/pty.d.ts +171 -0
- package/dist/sdk/pty.js +496 -0
- package/dist/sdk/sandbox.d.ts +537 -0
- package/dist/sdk/sandbox.js +725 -0
- package/dist/sdk/ssh.d.ts +25 -0
- package/dist/sdk/ssh.js +114 -0
- package/dist/sdk/trace.js +80 -0
- package/dist/sdk/transport-worker.js +466 -0
- package/dist/sdk/warm.js +40 -0
- package/dist/ssh.js +267 -0
- package/dist/surface.d.ts +95 -0
- package/dist/surface.js +1452 -0
- package/dist/templates.js +53 -0
- package/dist/term.js +50 -0
- package/dist/timing.js +71 -0
- package/dist/untar.js +324 -0
- package/dist/uploadguard.js +75 -0
- package/llms.txt +209 -0
- package/package.json +52 -0
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Sandbox`: a simple class for one sandbox (create, connect, commands.run, files, pty, fork, kill).
|
|
3
|
+
*
|
|
4
|
+
* `import { Sandbox } from '@promigence/sdk'` gives the familiar call shape; a call outside the
|
|
5
|
+
* supported set throws `UnsupportedError` naming the Promigence alternative.
|
|
6
|
+
*
|
|
7
|
+
* Mapping: a sandbox is a **fork of 1** from a verified snapshot — `Sandbox.create(snapshot)`
|
|
8
|
+
* is `POST /runs {count: 1}` resolved when the sandbox is ready; `allowInternetAccess: false`
|
|
9
|
+
* → `network: none`; `metadata` → run labels; `timeoutMs` → the sandbox timeout (billed per
|
|
10
|
+
* second used). Spend cap: `opts.spendCap` > `PROMIGENCE_SPEND_CAP` > `GET /me.default_spend_cap`.
|
|
11
|
+
*/
|
|
12
|
+
import { inspect, type InspectOptions } from "node:util";
|
|
13
|
+
import { type CommandResult, type CommandRunOpts, type ForkOpts, type OptimizeFor, type SandboxOpts, type Tier } from "./core.js";
|
|
14
|
+
import { PromigenceClient, type BackgroundExecRecord, type DirEntry, type DirListOpts, type ExtractResult, type FileInfo, type FileMatch, type Page, type PortRecord, type AutoPauseMode, type SandboxRecord, type SearchOpts, type SecretBinding, type SnapshotBuild, type VerifySpec } from "./client.js";
|
|
15
|
+
import { CommandHandle } from "./handles.js";
|
|
16
|
+
import type { PtyExit, PtySession, PtySize } from "./pty.js";
|
|
17
|
+
/**
|
|
18
|
+
* `commands.run` options for a foreground command. The call resolves with the whole result when
|
|
19
|
+
* the command ends; `onStdout` / `onStderr` also receive its output as it is written.
|
|
20
|
+
*/
|
|
21
|
+
export interface ForegroundRunOpts extends CommandRunOpts {
|
|
22
|
+
background?: false;
|
|
23
|
+
onStdout?: (data: string) => void;
|
|
24
|
+
onStderr?: (data: string) => void;
|
|
25
|
+
}
|
|
26
|
+
/** `commands.run` options for a background command: output callbacks instead of a result. */
|
|
27
|
+
export interface BackgroundRunOpts extends CommandRunOpts {
|
|
28
|
+
background: true;
|
|
29
|
+
onStdout?: (data: string) => void;
|
|
30
|
+
onStderr?: (data: string) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Keep standard input open, so the handle's `sendStdin` / `closeStdin` reach the process.
|
|
33
|
+
*
|
|
34
|
+
* Has to be decided here: a child's stdin cannot be opened once it has been spawned, so
|
|
35
|
+
* without it the process reads /dev/null for its whole life and a later write is refused.
|
|
36
|
+
*/
|
|
37
|
+
stdin?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** `Sandbox.list` / `Sandbox.listPage`: the client-side half of `SandboxListOptions`. */
|
|
40
|
+
export interface SandboxListStaticOpts {
|
|
41
|
+
client?: PromigenceClient;
|
|
42
|
+
limit?: number;
|
|
43
|
+
labels?: Record<string, string>;
|
|
44
|
+
state?: string[];
|
|
45
|
+
cursor?: string;
|
|
46
|
+
}
|
|
47
|
+
/** One running command, from `commands.list()`. `pid` is the `exec_id`. */
|
|
48
|
+
export interface ProcessInfo {
|
|
49
|
+
pid: string;
|
|
50
|
+
cmd: string;
|
|
51
|
+
state: BackgroundExecRecord["state"];
|
|
52
|
+
exitCode?: number;
|
|
53
|
+
}
|
|
54
|
+
/** One file or directory, from `files.list()`. */
|
|
55
|
+
export interface EntryInfo {
|
|
56
|
+
name: string;
|
|
57
|
+
path: string;
|
|
58
|
+
type: "file" | "dir";
|
|
59
|
+
size: number;
|
|
60
|
+
/** Numeric mode bits (`0o100644`). */
|
|
61
|
+
mode: number;
|
|
62
|
+
/** `rwxr-xr-x`. */
|
|
63
|
+
permissions: string;
|
|
64
|
+
modifiedTime: Date;
|
|
65
|
+
/** `lstat`, not `stat`: a symlink is reported as one and not followed. */
|
|
66
|
+
isSymlink: boolean;
|
|
67
|
+
}
|
|
68
|
+
export interface PtyCreateOpts extends Partial<PtySize> {
|
|
69
|
+
/** Terminal output, as bytes. */
|
|
70
|
+
onData?: (data: Uint8Array) => void;
|
|
71
|
+
onExit?: (exit: PtyExit) => void;
|
|
72
|
+
/** Working directory for the shell. */
|
|
73
|
+
cwd?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Plain environment variables, composed into the command as `export K=v;`.
|
|
76
|
+
*
|
|
77
|
+
* **Do not put a credential here.** Use `secrets` — the value is then resolved server-side
|
|
78
|
+
* and never appears in the command text at all. `envs` is for the things you would not mind
|
|
79
|
+
* seeing in `ps`.
|
|
80
|
+
*/
|
|
81
|
+
envs?: Record<string, string>;
|
|
82
|
+
/**
|
|
83
|
+
* Stored secret names, or `{ name, as }` bindings, put into the terminal's environment by the
|
|
84
|
+
* server. The value never leaves the service and is never part of the command.
|
|
85
|
+
*/
|
|
86
|
+
secrets?: SecretBinding[];
|
|
87
|
+
/** What to run instead of the login shell. */
|
|
88
|
+
cmd?: string;
|
|
89
|
+
/** Handshake bound (default 30 s). */
|
|
90
|
+
timeoutMs?: number;
|
|
91
|
+
/**
|
|
92
|
+
* When the connection drops, or the service is updated, the same terminal is picked up again
|
|
93
|
+
* over a new connection, where it left off: the same shell or command, still running.
|
|
94
|
+
* Default: on.
|
|
95
|
+
*/
|
|
96
|
+
resume?: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* When the service is updated and the terminal cannot be picked up again, the session goes on
|
|
99
|
+
* over a new connection in a NEW shell (what ran in the old one has ended), with its callbacks
|
|
100
|
+
* and its size, for up to 30 s of trying; past that it ends with `error.code`
|
|
101
|
+
* `"service_restart"`. Default: on for the login shell, off with `cmd` (reconnecting would start
|
|
102
|
+
* the command again).
|
|
103
|
+
*/
|
|
104
|
+
reconnect?: boolean;
|
|
105
|
+
/** Called after each reconnect: `resumed` says whether it is the same terminal or a new shell. */
|
|
106
|
+
onReconnected?: (how: {
|
|
107
|
+
resumed: boolean;
|
|
108
|
+
}) => void;
|
|
109
|
+
}
|
|
110
|
+
/** The default terminal command. */
|
|
111
|
+
export declare const DEFAULT_PTY_CMD = "TERM=${TERM:-xterm-256color} exec /bin/sh -l";
|
|
112
|
+
/** POSIX single-quote one word for `sh`. */
|
|
113
|
+
export declare function shellQuote(s: string): string;
|
|
114
|
+
/**
|
|
115
|
+
* The one `cmd` the terminal route takes, with `cwd` and `envs` composed in front of it.
|
|
116
|
+
* `undefined` when there is nothing to compose, so the default applies.
|
|
117
|
+
*/
|
|
118
|
+
export declare function ptyCommand(opts: {
|
|
119
|
+
cmd?: string;
|
|
120
|
+
cwd?: string;
|
|
121
|
+
envs?: Record<string, string>;
|
|
122
|
+
}): string | undefined;
|
|
123
|
+
export declare function toEntryInfo(e: DirEntry): EntryInfo;
|
|
124
|
+
/**
|
|
125
|
+
* `mkdir` / `move` / `copy` / `chmod` answer with a path and no name, because the path is what
|
|
126
|
+
* the caller named. `EntryInfo` has both, so the basename is filled in here rather than left
|
|
127
|
+
* empty: a handle that returns half a record for four of its verbs is a handle nobody can write
|
|
128
|
+
* one loop against.
|
|
129
|
+
*/
|
|
130
|
+
export declare function toEntryInfoFromPath(f: FileInfo): EntryInfo;
|
|
131
|
+
export interface SandboxCreateOpts extends SandboxOpts {
|
|
132
|
+
/** Reuse an existing client (tests, or one client per process). */
|
|
133
|
+
client?: PromigenceClient;
|
|
134
|
+
/** `snap_<id>` | `<alias>` | `<alias>@<commit7>`; the same as the first argument. */
|
|
135
|
+
snapshot?: string;
|
|
136
|
+
/**
|
|
137
|
+
* A container image instead of a snapshot — a tag (`python:3.12`, pinned to its digest by the
|
|
138
|
+
* API) or `registry/name@sha256:<64 hex>`: the snapshot of this image is built on first use
|
|
139
|
+
* (a new build is billed per second while it runs, at its tier's rate, `client.pricing()`; pass
|
|
140
|
+
* `allowBuild: true` to allow it) and
|
|
141
|
+
* reused after (same digest + same inputs → the same snapshot). A name with no tag or digest is
|
|
142
|
+
* refused: it would pin whatever `:latest` is today. The fields below shape that snapshot and
|
|
143
|
+
* are ignored without `image`.
|
|
144
|
+
*/
|
|
145
|
+
image?: string;
|
|
146
|
+
setup?: string[];
|
|
147
|
+
/** Without it the image snapshot is stored `verified: false`. */
|
|
148
|
+
verify?: VerifySpec;
|
|
149
|
+
/** A background process started before the snapshot, so every fork inherits it running. */
|
|
150
|
+
start?: string | string[];
|
|
151
|
+
tier?: Tier;
|
|
152
|
+
alias?: string;
|
|
153
|
+
/** Name of a stored secret holding the registry credentials. */
|
|
154
|
+
registrySecret?: string;
|
|
155
|
+
/** Bound on the first build of an image (default 15 min). Expiry cancels nothing. */
|
|
156
|
+
buildTimeoutMs?: number;
|
|
157
|
+
/**
|
|
158
|
+
* Let `Sandbox.create({ image })` build the image's snapshot when none exists yet. A new build
|
|
159
|
+
* is billed per second while it runs, at most `build_price` (your plan's rates, `client.pricing()`);
|
|
160
|
+
* reusing a snapshot already built is free. Without it, a create from an image is refused before anything is sent: whether the
|
|
161
|
+
* image's snapshot exists is only known once a build is submitted, and a submitted build cannot
|
|
162
|
+
* be withdrawn. The other way to pay once and on purpose: `promigence snapshot create --image
|
|
163
|
+
* REF --alias NAME`, then `Sandbox.create("NAME")`.
|
|
164
|
+
*/
|
|
165
|
+
allowBuild?: boolean;
|
|
166
|
+
/**
|
|
167
|
+
* Called with the `POST /snapshots` answer before any wait: `build_price` (the most the build can
|
|
168
|
+
* cost) and `per_second_usd`, and `deduped` or `joined` when nothing new is charged. Without it,
|
|
169
|
+
* a new build's price is reported as a process warning (stderr) before the build is waited for.
|
|
170
|
+
*/
|
|
171
|
+
onBuild?: (build: SnapshotBuild) => void | Promise<void>;
|
|
172
|
+
/**
|
|
173
|
+
* Abort the create. Whatever it had started is ended (nothing is left running, or billed, for
|
|
174
|
+
* nobody), then it rejects with `TimeoutError` ("aborted by the caller's signal").
|
|
175
|
+
*/
|
|
176
|
+
signal?: AbortSignal;
|
|
177
|
+
/**
|
|
178
|
+
* Stored secrets the sandbox receives, as environment variables: a name binds the secret to a
|
|
179
|
+
* variable of the same name, `{ name, as }` to a different one. Every command run against the
|
|
180
|
+
* sandbox gets them. As `Sandbox.fork` takes them.
|
|
181
|
+
*/
|
|
182
|
+
secrets?: SecretBinding[];
|
|
183
|
+
/**
|
|
184
|
+
* The only destinations the sandbox may reach: `["github.com", "*.npmjs.org"]`. Everything
|
|
185
|
+
* else is refused, and the refusal names the host. It wins over `allowInternetAccess`. As
|
|
186
|
+
* `Sandbox.fork` takes it.
|
|
187
|
+
*/
|
|
188
|
+
allowHosts?: string[];
|
|
189
|
+
/** What to favour, `start` or `compute`. As `Sandbox.fork` takes it. */
|
|
190
|
+
optimizeFor?: OptimizeFor;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Create-or-reuse the snapshot for an image digest and return its `snapshot_id`.
|
|
194
|
+
*
|
|
195
|
+
* `POST /snapshots {image}` answers 200 with the existing snapshot when this digest (with the same
|
|
196
|
+
* inputs) was built before, or 202 with a `build_id`. The **body**, not the status, decides: an
|
|
197
|
+
* idempotency replay answers 202 with a document that may already be `verified`.
|
|
198
|
+
*/
|
|
199
|
+
export declare function imageSnapshot(client: PromigenceClient, opts: Pick<SandboxCreateOpts, "image" | "setup" | "verify" | "start" | "tier" | "alias" | "registrySecret" | "buildTimeoutMs">, hooks?: {
|
|
200
|
+
/**
|
|
201
|
+
* The `POST /snapshots` answer, before any wait: `build_price` (the most it can cost) and
|
|
202
|
+
* whether it was `deduped` or `joined` (nothing new charged). An implicit build costs money, so a caller that prints prices prints this one too.
|
|
203
|
+
*/
|
|
204
|
+
onBuild?: (build: SnapshotBuild) => void | Promise<void>;
|
|
205
|
+
/** Ends the wait for a build at once; the build itself, once submitted, is not withdrawn. */
|
|
206
|
+
signal?: AbortSignal;
|
|
207
|
+
}): Promise<string>;
|
|
208
|
+
/** `sandbox.fork()` options: `onReady` is handed each new `Sandbox`. */
|
|
209
|
+
export type SandboxInstanceForkOpts = Omit<ForkOpts, "onReady"> & {
|
|
210
|
+
onReady?: (sandbox: Sandbox, index: number) => void;
|
|
211
|
+
};
|
|
212
|
+
export interface SandboxForkOpts extends Omit<ForkOpts, "onReady"> {
|
|
213
|
+
/** Called with each `Sandbox` as it becomes ready. */
|
|
214
|
+
onReady?: (sandbox: Sandbox, index: number) => void;
|
|
215
|
+
client?: PromigenceClient;
|
|
216
|
+
apiKey?: string;
|
|
217
|
+
apiUrl?: string;
|
|
218
|
+
spendCap?: number;
|
|
219
|
+
timeoutMs?: number;
|
|
220
|
+
metadata?: Record<string, string>;
|
|
221
|
+
/**
|
|
222
|
+
* Stored secrets every sandbox of this fork receives, as environment variables.
|
|
223
|
+
*
|
|
224
|
+
* A string binds a secret to a variable of the same name; `{ name, as }` binds it to a
|
|
225
|
+
* different one — which is how a pool of workers each hold their own value for one variable:
|
|
226
|
+
*
|
|
227
|
+
* ```ts
|
|
228
|
+
* await Sandbox.create({ secrets: [{ name: `work_secret_${i}`, as: "ANTHROPIC_WORK_SECRET" }] });
|
|
229
|
+
* ```
|
|
230
|
+
*
|
|
231
|
+
* Every command run against the sandbox gets them, background execs included, so a
|
|
232
|
+
* credentialed worker does not have to hold a streaming exec open for its whole life.
|
|
233
|
+
*/
|
|
234
|
+
secrets?: SecretBinding[];
|
|
235
|
+
allowInternetAccess?: boolean;
|
|
236
|
+
/**
|
|
237
|
+
* The only destinations this sandbox may reach: `["github.com", "*.npmjs.org"]`. Everything
|
|
238
|
+
* else is refused, and the refusal names the host rather than hanging.
|
|
239
|
+
*
|
|
240
|
+
* What it is, so you can decide whether it is enough: the runtime resolves the names you list
|
|
241
|
+
* and permits exactly the addresses they answer with, for as long as their TTL says. That is
|
|
242
|
+
* an address-level fence gated on names, not enforcement at the TLS layer — a host sharing an
|
|
243
|
+
* address with one you allowed is reachable.
|
|
244
|
+
*/
|
|
245
|
+
allowHosts?: string[];
|
|
246
|
+
optimizeFor?: OptimizeFor;
|
|
247
|
+
}
|
|
248
|
+
interface SandboxInit {
|
|
249
|
+
sandboxId: string;
|
|
250
|
+
runId: string;
|
|
251
|
+
snapshot: string;
|
|
252
|
+
client: PromigenceClient;
|
|
253
|
+
envs?: Record<string, string>;
|
|
254
|
+
timeoutMs?: number;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* The snapshot `Sandbox.create()` forks when it is given none: Debian 12 + Python 3.12 (pip, venv, uv),
|
|
258
|
+
* Node 24 (npm), Bun, Go 1.27, Docker, git, Git LFS, the GitHub CLI, curl, jq, ripgrep, rsync, gcc/make,
|
|
259
|
+
* and the Claude Code, Codex, Gemini CLI and OpenCode agents, `small` tier (built in, not verified). It
|
|
260
|
+
* is always ready to start. The template name `'base'` means the same thing.
|
|
261
|
+
*/
|
|
262
|
+
export declare const DEFAULT_SNAPSHOT = "promigence/base";
|
|
263
|
+
/**
|
|
264
|
+
* `opts.spendCap` > `PROMIGENCE_SPEND_CAP`, or `undefined` for "the org default".
|
|
265
|
+
*
|
|
266
|
+
* Deliberately no `GET /me`: the API already applies the org's `default_spend_cap` to a run that
|
|
267
|
+
* names none, so asking first would only add a round trip to every `Sandbox.create()`.
|
|
268
|
+
*/
|
|
269
|
+
export declare function spendCapFromEnv(spendCap?: number): number | undefined;
|
|
270
|
+
/** `opts.spendCap` > `PROMIGENCE_SPEND_CAP` > `GET /me.default_spend_cap`; none → InvalidArgumentError. */
|
|
271
|
+
export declare function resolveSpendCap(client: PromigenceClient, spendCap?: number): Promise<number>;
|
|
272
|
+
export declare class Sandbox {
|
|
273
|
+
#private;
|
|
274
|
+
readonly sandboxId: string;
|
|
275
|
+
/** The run this sandbox belongs to (`promigence run report <run_id>`). */
|
|
276
|
+
readonly runId: string;
|
|
277
|
+
/** The snapshot this sandbox was forked from — the origin for `fork()`. */
|
|
278
|
+
readonly snapshot: string;
|
|
279
|
+
/** Not `readonly`: `setTimeout` moves it, and later `commands.run` calls inherit it. */
|
|
280
|
+
private timeoutMs;
|
|
281
|
+
/** Any exec / write makes the sandbox dirty: `fork()` then needs `{fromOrigin: true}`. */
|
|
282
|
+
private dirty;
|
|
283
|
+
readonly commands: {
|
|
284
|
+
run(cmd: string, opts: BackgroundRunOpts): Promise<CommandHandle>;
|
|
285
|
+
/**
|
|
286
|
+
* Run `cmd` and resolve with its result. A non-zero exit throws `CommandExitError`; a command
|
|
287
|
+
* killed at its own `timeoutMs` throws `CommandTimeoutError` (a `CommandExitError` too).
|
|
288
|
+
*/
|
|
289
|
+
run(cmd: string, opts?: ForegroundRunOpts): Promise<CommandResult>;
|
|
290
|
+
/** Background commands in this sandbox (running and ended, until killed with forget). */
|
|
291
|
+
list(): Promise<ProcessInfo[]>;
|
|
292
|
+
/** SIGKILL a background command. `false` if it had already ended. */
|
|
293
|
+
kill(pid: string): Promise<boolean>;
|
|
294
|
+
/** Re-attach to a background command; output is replayed from its first byte. */
|
|
295
|
+
connect(pid: string, opts?: Pick<BackgroundRunOpts, "onStdout" | "onStderr">): Promise<CommandHandle>;
|
|
296
|
+
/**
|
|
297
|
+
* Write to a background command's stdin, by pid. The handle's own `sendStdin` is the same
|
|
298
|
+
* call; this spelling exists because a caller who only kept the pid should not have to
|
|
299
|
+
* `connect()` first just to write a line.
|
|
300
|
+
*/
|
|
301
|
+
sendStdin(pid: string, data: string | Uint8Array): Promise<number>;
|
|
302
|
+
/** Close its stdin (EOF). `sort`, `cat` and every REPL do nothing until this arrives. */
|
|
303
|
+
closeStdin(pid: string): Promise<void>;
|
|
304
|
+
};
|
|
305
|
+
/**
|
|
306
|
+
* Interactive terminals (`sandbox.pty`). `create` resolves once the terminal exists;
|
|
307
|
+
* the returned session's `pid` is what `sendInput` / `resize` / `kill` address.
|
|
308
|
+
*/
|
|
309
|
+
readonly pty: {
|
|
310
|
+
create(opts?: PtyCreateOpts): Promise<PtySession>;
|
|
311
|
+
sendInput(pid: number, data: Uint8Array | string): Promise<void>;
|
|
312
|
+
resize(pid: number, size: PtySize): Promise<void>;
|
|
313
|
+
kill(pid: number): Promise<boolean>;
|
|
314
|
+
};
|
|
315
|
+
/** Preview URLs for ports inside the sandbox (`getHost` gives the address alone). */
|
|
316
|
+
readonly ports: {
|
|
317
|
+
expose(port: number): Promise<PortRecord>;
|
|
318
|
+
list(): Promise<PortRecord[]>;
|
|
319
|
+
/** A token revokes that URL; a port number every URL for it. Returns the revoked tokens. */
|
|
320
|
+
revoke(tokenOrPort: string | number): Promise<string[]>;
|
|
321
|
+
};
|
|
322
|
+
/** Terminals opened from this object, by pid: a terminal belongs to its connection. */
|
|
323
|
+
private readonly terminals;
|
|
324
|
+
readonly files: {
|
|
325
|
+
read(path: string, opts?: {
|
|
326
|
+
format?: "text";
|
|
327
|
+
}): Promise<string>;
|
|
328
|
+
read(path: string, opts: {
|
|
329
|
+
format: "bytes";
|
|
330
|
+
}): Promise<Uint8Array>;
|
|
331
|
+
/**
|
|
332
|
+
* Text is written as UTF-8; bytes as they are (a typed array, an `ArrayBuffer` or a `Blob`).
|
|
333
|
+
* A file that already exists keeps its mode, as a shell `>` or an editor's save does; a new
|
|
334
|
+
* one is `0o644`. `{ mode: 0o755 }` sets the mode either way.
|
|
335
|
+
*/
|
|
336
|
+
write(path: string, data: string | Uint8Array | ArrayBuffer | ArrayBufferView | Blob, opts?: {
|
|
337
|
+
mode?: number;
|
|
338
|
+
}): Promise<void>;
|
|
339
|
+
remove(path: string, opts?: {
|
|
340
|
+
recursive?: boolean;
|
|
341
|
+
}): Promise<void>;
|
|
342
|
+
exists(path: string): Promise<boolean>;
|
|
343
|
+
list(path?: string, opts?: DirListOpts): Promise<EntryInfo[]>;
|
|
344
|
+
mkdir(path: string, opts?: {
|
|
345
|
+
mode?: number | string;
|
|
346
|
+
parents?: boolean;
|
|
347
|
+
}): Promise<EntryInfo>;
|
|
348
|
+
move(from: string, to: string, opts?: {
|
|
349
|
+
overwrite?: boolean;
|
|
350
|
+
}): Promise<EntryInfo>;
|
|
351
|
+
/** Another name for `move`. Same call. */
|
|
352
|
+
rename(from: string, to: string, opts?: {
|
|
353
|
+
overwrite?: boolean;
|
|
354
|
+
}): Promise<EntryInfo>;
|
|
355
|
+
copy(from: string, to: string, opts?: {
|
|
356
|
+
recursive?: boolean;
|
|
357
|
+
overwrite?: boolean;
|
|
358
|
+
}): Promise<EntryInfo>;
|
|
359
|
+
chmod(path: string, opts: {
|
|
360
|
+
mode?: number | string;
|
|
361
|
+
uid?: number;
|
|
362
|
+
gid?: number;
|
|
363
|
+
recursive?: boolean;
|
|
364
|
+
}): Promise<EntryInfo>;
|
|
365
|
+
search(path: string, opts: SearchOpts): Promise<FileMatch[]>;
|
|
366
|
+
downloadDir(path: string, opts?: {
|
|
367
|
+
exclude?: string[];
|
|
368
|
+
}): Promise<Uint8Array>;
|
|
369
|
+
uploadDir(tar: Uint8Array, into: string, opts?: {
|
|
370
|
+
strip?: number;
|
|
371
|
+
}): Promise<ExtractResult>;
|
|
372
|
+
};
|
|
373
|
+
protected constructor(init: SandboxInit);
|
|
374
|
+
/**
|
|
375
|
+
* Fork of 1 from a snapshot (`snap_<id>` | `<alias>` | `<alias>@<commit7>`), or from the
|
|
376
|
+
* snapshot of an image: `Sandbox.create({ image: 'python:3.12', allowBuild: true })` builds it
|
|
377
|
+
* on first use (a new build billed per second at its tier's rate, bounded by `buildTimeoutMs`, default 15 min) and reuses it
|
|
378
|
+
* free after. An image needs `allowBuild: true` and a tag or digest; without either it is
|
|
379
|
+
* refused before any request.
|
|
380
|
+
*
|
|
381
|
+
* A create still queued when `waitTimeoutMs` runs out throws `TimeoutError` and leaves nothing
|
|
382
|
+
* behind: its run is cancelled, so the sandbox cannot start later with nobody holding it. Any
|
|
383
|
+
* other failure of the wait cancels the run the same way and throws what the wait threw.
|
|
384
|
+
*/
|
|
385
|
+
static create(opts?: SandboxCreateOpts): Promise<Sandbox>;
|
|
386
|
+
static create(snapshotIdOrAlias?: string, opts?: SandboxCreateOpts): Promise<Sandbox>;
|
|
387
|
+
/** `Sandbox.fork(snapshot, {count})` — resolves when every handle is ready. */
|
|
388
|
+
static fork(snapshotIdOrAlias: string, opts?: SandboxForkOpts): Promise<Sandbox[]>;
|
|
389
|
+
/**
|
|
390
|
+
* Native form of `fork`: `POST /runs` returns immediately and each handle resolves as its
|
|
391
|
+
* sandbox becomes ready.
|
|
392
|
+
*/
|
|
393
|
+
static forkHandles(snapshotIdOrAlias: string, opts?: SandboxForkOpts): Promise<{
|
|
394
|
+
runId: string;
|
|
395
|
+
handles: Array<Promise<Sandbox>>;
|
|
396
|
+
}>;
|
|
397
|
+
/**
|
|
398
|
+
* `forkHandles`, plus what `create` needs to end a run it was interrupted starting: the key the
|
|
399
|
+
* create is sent under, a signal for it and its waits, and the start options as sent.
|
|
400
|
+
*/
|
|
401
|
+
private static forkHandlesWith;
|
|
402
|
+
/** Attach to a running sandbox (`GET /sandboxes/:id`). */
|
|
403
|
+
static connect(sandboxId: string, opts?: SandboxCreateOpts): Promise<Sandbox>;
|
|
404
|
+
/**
|
|
405
|
+
* `GET /sandboxes?limit=[&labels=][&state=][&cursor=]` — this org's sandboxes, newest first.
|
|
406
|
+
*
|
|
407
|
+
* A plain array: every caller iterates it, and that is the shape that keeps working. The page
|
|
408
|
+
* behind it — the cursor to the next one — is [`listPage`].
|
|
409
|
+
*/
|
|
410
|
+
static list(opts?: SandboxListStaticOpts): Promise<SandboxRecord[]>;
|
|
411
|
+
/**
|
|
412
|
+
* One page, with the cursor that follows it: `{ items, nextCursor, limit }`.
|
|
413
|
+
*
|
|
414
|
+
* `nextCursor` is `null` on the last page and **that is the only stop condition** — a short
|
|
415
|
+
* page is not one, because `labels` and `state` are filtered server-side and can empty a page
|
|
416
|
+
* that still has successors. `labels` filtering is why this exists at all: `limit` bounds the
|
|
417
|
+
* rows the server *reads*, so filtering the returned array cannot see a session's sandbox
|
|
418
|
+
* older than the first page, which is what made "find it or fork it" unwritable against us.
|
|
419
|
+
*/
|
|
420
|
+
static listPage(opts?: SandboxListStaticOpts): Promise<Page<SandboxRecord>>;
|
|
421
|
+
/**
|
|
422
|
+
* Forks the **origin snapshot** this sandbox started from. To fork the sandbox as it is now,
|
|
423
|
+
* take a live snapshot (`client.sandboxes.snapshot(sandboxId)`) and `Sandbox.fork()` that.
|
|
424
|
+
*/
|
|
425
|
+
fork(opts?: SandboxInstanceForkOpts): Promise<Sandbox[]>;
|
|
426
|
+
/**
|
|
427
|
+
* What `JSON.stringify` shows: the ids. The client, its API key and the create-time `envs` are
|
|
428
|
+
* private fields, so a logger, an error tracker or a tool result that serialises the sandbox
|
|
429
|
+
* never carries them.
|
|
430
|
+
*/
|
|
431
|
+
toJSON(): {
|
|
432
|
+
sandboxId: string;
|
|
433
|
+
runId: string;
|
|
434
|
+
snapshot: string;
|
|
435
|
+
};
|
|
436
|
+
/** What `console.log` / `util.inspect` show: the same as `toJSON`. */
|
|
437
|
+
[inspect.custom](_depth: number, opts: InspectOptions): string;
|
|
438
|
+
/** `DELETE /sandboxes/:id`. */
|
|
439
|
+
/** End the sandbox. `false` when it had already ended (the API answers `already_ended`). */
|
|
440
|
+
kill(): Promise<boolean>;
|
|
441
|
+
/** `GET /sandboxes/:id`. */
|
|
442
|
+
getInfo(): Promise<SandboxRecord>;
|
|
443
|
+
/**
|
|
444
|
+
* `POST /sandboxes/:id/probe` — is this environment still the one that was verified?
|
|
445
|
+
*
|
|
446
|
+
* `first_bad_path` is the **first differing path**, which is the only actionable part.
|
|
447
|
+
*/
|
|
448
|
+
probe(opts?: {
|
|
449
|
+
paths?: string[];
|
|
450
|
+
}): Promise<{
|
|
451
|
+
sandbox_id: string;
|
|
452
|
+
ok: boolean;
|
|
453
|
+
ms: number;
|
|
454
|
+
checked: string | string[];
|
|
455
|
+
first_bad_path?: string | null;
|
|
456
|
+
}>;
|
|
457
|
+
isRunning(): Promise<boolean>;
|
|
458
|
+
/**
|
|
459
|
+
* `PATCH /sandboxes/:id` — extend this sandbox's timeout.
|
|
460
|
+
*
|
|
461
|
+
* The timeout is the sandbox's total lifetime, not "from now", and the difference is billing:
|
|
462
|
+
* commits *seconds* up front and `billable_seconds <= committed_seconds`, so an extension is a new
|
|
463
|
+
* commitment that has to fit under the spend cap you set (the run's, or the org default). It throws
|
|
464
|
+
* `SpendCapError` (409) rather than silently extending — which is the behaviour a spend
|
|
465
|
+
* cap exists to produce, and the one difference here worth a caller knowing about.
|
|
466
|
+
*/
|
|
467
|
+
setTimeout(ms: number): Promise<void>;
|
|
468
|
+
/**
|
|
469
|
+
* Pause this sandbox once it has been idle for `seconds`; `0` means it never does.
|
|
470
|
+
*
|
|
471
|
+
* It is the cheap half of a spend cap: the timeout is the bound you committed to, this is what
|
|
472
|
+
* stops you spending it on a session nobody is driving. A command still running counts as
|
|
473
|
+
* busy, so a long build is never cut short by it, and the server keeps a floor under how short
|
|
474
|
+
* the window may be. Bring it back with `resume()`, which is the warm path.
|
|
475
|
+
*
|
|
476
|
+
* `mode: "activity"` is for an agent that runs inside the sandbox on its own: it also waits
|
|
477
|
+
* until nothing inside has used CPU, moved a byte or held a connection open for the window
|
|
478
|
+
* (`AutoPauseMode`). Omitted, the mode is left as it is (`"requests"` unless set).
|
|
479
|
+
*/
|
|
480
|
+
setAutoPause(seconds: number, mode?: AutoPauseMode): Promise<void>;
|
|
481
|
+
/** The idle rule in force: seconds before it pauses itself, `0` when it never does. */
|
|
482
|
+
getAutoPause(): Promise<number>;
|
|
483
|
+
/**
|
|
484
|
+
* Cut this sandbox's egress, now. Nothing it runs afterwards can reach the network.
|
|
485
|
+
*
|
|
486
|
+
* The sequence this is for: fork with the network on, install what the task needs, call this,
|
|
487
|
+
* *then* let the agent run. The policy used to be fixed at fork, so an eval harness that wanted
|
|
488
|
+
* a network for setup and none for the rollout had to choose one of the two.
|
|
489
|
+
*
|
|
490
|
+
* There is no matching `enableInternet`. Egress goes one way — a sandbox that could re-open
|
|
491
|
+
* its own network on request is not one whose egress you can reason about.
|
|
492
|
+
*/
|
|
493
|
+
disableInternet(): Promise<void>;
|
|
494
|
+
/**
|
|
495
|
+
* The preview address for `port`, **without a scheme**, so callers write
|
|
496
|
+
* `` `https://${host}` ``. The address may be plain `http://`; `ports.expose(port)` returns the
|
|
497
|
+
* full `url` with its scheme.
|
|
498
|
+
*
|
|
499
|
+
* Async, because the address is a capability minted on demand rather than
|
|
500
|
+
* a hostname derived from the id. An existing URL for the port is reused, not re-minted.
|
|
501
|
+
*/
|
|
502
|
+
getHost(port: number): Promise<string>;
|
|
503
|
+
/**
|
|
504
|
+
* Pause this sandbox. From the answer on it bills no seconds and holds no capacity. Its files
|
|
505
|
+
* and memory are kept until `resume()` or `kill()`, and `resume()` brings it back as it was.
|
|
506
|
+
*
|
|
507
|
+
* Background execs (started with `background: true`) end at the pause: their exec ids answer
|
|
508
|
+
* not found after `resume()`, and `backgroundExecsKilled` says how many. Anything else you
|
|
509
|
+
* started keeps running when the sandbox resumes.
|
|
510
|
+
*
|
|
511
|
+
* A pause can take seconds on a large, busy sandbox and under a second on a small, quiet one;
|
|
512
|
+
* `pauseMs` (also `tookMs`) is how long it took. `resume()` is the fast half; its `resumeMs`
|
|
513
|
+
* (also `tookMs`) is how long that took.
|
|
514
|
+
*/
|
|
515
|
+
pause(): Promise<{
|
|
516
|
+
pausedId: string;
|
|
517
|
+
tookMs?: number;
|
|
518
|
+
pauseMs?: number;
|
|
519
|
+
bytes?: {
|
|
520
|
+
allocated: number;
|
|
521
|
+
};
|
|
522
|
+
alreadyPaused?: boolean;
|
|
523
|
+
backgroundExecsKilled?: number;
|
|
524
|
+
warnings?: string[];
|
|
525
|
+
}>;
|
|
526
|
+
/**
|
|
527
|
+
* Bring a paused sandbox back, as it was when it was paused. Typically well under a second.
|
|
528
|
+
* `optimizeFor` left out keeps the sandbox's own setting.
|
|
529
|
+
*/
|
|
530
|
+
resume(opts?: {
|
|
531
|
+
optimizeFor?: OptimizeFor;
|
|
532
|
+
}): Promise<{
|
|
533
|
+
tookMs?: number;
|
|
534
|
+
resumeMs?: number;
|
|
535
|
+
}>;
|
|
536
|
+
}
|
|
537
|
+
export {};
|