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.
Files changed (97) hide show
  1. package/NOTICE +14 -0
  2. package/README.md +88 -0
  3. package/dist/account.js +850 -0
  4. package/dist/agent.js +374 -0
  5. package/dist/argv.js +159 -0
  6. package/dist/bin.js +332 -0
  7. package/dist/bundle.js +133 -0
  8. package/dist/capacity.js +69 -0
  9. package/dist/commands.d.ts +110 -0
  10. package/dist/commands.js +2675 -0
  11. package/dist/connectreq.js +125 -0
  12. package/dist/credfile.js +188 -0
  13. package/dist/credits.js +197 -0
  14. package/dist/devcontainer.d.ts +99 -0
  15. package/dist/devcontainer.js +744 -0
  16. package/dist/device.js +129 -0
  17. package/dist/dirsnap.js +378 -0
  18. package/dist/errfix.js +262 -0
  19. package/dist/generated.d.ts +35 -0
  20. package/dist/generated.js +307 -0
  21. package/dist/github.js +307 -0
  22. package/dist/gitlab.js +210 -0
  23. package/dist/guide.d.ts +19 -0
  24. package/dist/guide.js +366 -0
  25. package/dist/handlers.js +511 -0
  26. package/dist/index.d.ts +14 -0
  27. package/dist/index.js +7 -0
  28. package/dist/init.d.ts +40 -0
  29. package/dist/init.js +352 -0
  30. package/dist/install.d.ts +23 -0
  31. package/dist/install.js +127 -0
  32. package/dist/io.d.ts +37 -0
  33. package/dist/io.js +318 -0
  34. package/dist/live.js +469 -0
  35. package/dist/login.js +1063 -0
  36. package/dist/mcp.js +889 -0
  37. package/dist/money.js +5 -0
  38. package/dist/orgs.js +475 -0
  39. package/dist/pricing.d.ts +52 -0
  40. package/dist/pricing.js +181 -0
  41. package/dist/report.js +132 -0
  42. package/dist/routes.js +135 -0
  43. package/dist/runners-github.js +257 -0
  44. package/dist/runners-gitlab.js +125 -0
  45. package/dist/runners-spec.js +137 -0
  46. package/dist/runners.js +1458 -0
  47. package/dist/sdk/blake3.d.ts +10 -0
  48. package/dist/sdk/blake3.js +111 -0
  49. package/dist/sdk/bundle.d.ts +96 -0
  50. package/dist/sdk/bundle.js +227 -0
  51. package/dist/sdk/ca-guard.js +166 -0
  52. package/dist/sdk/caller.d.ts +73 -0
  53. package/dist/sdk/caller.js +47 -0
  54. package/dist/sdk/client.d.ts +3015 -0
  55. package/dist/sdk/client.js +2583 -0
  56. package/dist/sdk/command-errors.d.ts +41 -0
  57. package/dist/sdk/command-errors.js +36 -0
  58. package/dist/sdk/context.d.ts +119 -0
  59. package/dist/sdk/context.js +588 -0
  60. package/dist/sdk/core.d.ts +285 -0
  61. package/dist/sdk/core.js +266 -0
  62. package/dist/sdk/credstore.d.ts +90 -0
  63. package/dist/sdk/credstore.js +206 -0
  64. package/dist/sdk/dispatcher.js +86 -0
  65. package/dist/sdk/github.d.ts +158 -0
  66. package/dist/sdk/github.js +78 -0
  67. package/dist/sdk/gitlab.d.ts +104 -0
  68. package/dist/sdk/gitlab.js +20 -0
  69. package/dist/sdk/handles.d.ts +82 -0
  70. package/dist/sdk/handles.js +135 -0
  71. package/dist/sdk/hint.js +7 -0
  72. package/dist/sdk/http2.js +1921 -0
  73. package/dist/sdk/index.d.ts +34 -0
  74. package/dist/sdk/index.js +15 -0
  75. package/dist/sdk/keyed.gen.js +7 -0
  76. package/dist/sdk/models.gen.d.ts +6162 -0
  77. package/dist/sdk/models.gen.js +1 -0
  78. package/dist/sdk/proxy.js +249 -0
  79. package/dist/sdk/pty.d.ts +171 -0
  80. package/dist/sdk/pty.js +496 -0
  81. package/dist/sdk/sandbox.d.ts +537 -0
  82. package/dist/sdk/sandbox.js +725 -0
  83. package/dist/sdk/ssh.d.ts +25 -0
  84. package/dist/sdk/ssh.js +114 -0
  85. package/dist/sdk/trace.js +80 -0
  86. package/dist/sdk/transport-worker.js +466 -0
  87. package/dist/sdk/warm.js +40 -0
  88. package/dist/ssh.js +267 -0
  89. package/dist/surface.d.ts +95 -0
  90. package/dist/surface.js +1452 -0
  91. package/dist/templates.js +53 -0
  92. package/dist/term.js +50 -0
  93. package/dist/timing.js +71 -0
  94. package/dist/untar.js +324 -0
  95. package/dist/uploadguard.js +75 -0
  96. package/llms.txt +209 -0
  97. 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 {};