@boatdev/sdk 1.2.0 → 1.3.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.
Files changed (36) hide show
  1. package/.openapi-generator/FILES +2 -0
  2. package/dist/apis/BoatApi.d.ts +2 -2
  3. package/dist/apis/BoatApi.js +2 -2
  4. package/dist/boat-helpers.d.ts +17 -1
  5. package/dist/boat-helpers.js +61 -0
  6. package/dist/esm/apis/BoatApi.d.ts +2 -2
  7. package/dist/esm/apis/BoatApi.js +2 -2
  8. package/dist/esm/boat-helpers.d.ts +17 -1
  9. package/dist/esm/boat-helpers.js +60 -0
  10. package/dist/esm/models/CommandRequest.d.ts +6 -0
  11. package/dist/esm/models/CommandRequest.js +2 -0
  12. package/dist/esm/models/CommandStreamFrame.d.ts +85 -0
  13. package/dist/esm/models/CommandStreamFrame.js +67 -0
  14. package/dist/esm/models/CreateSandboxRequest.d.ts +6 -0
  15. package/dist/esm/models/CreateSandboxRequest.js +2 -0
  16. package/dist/esm/models/index.d.ts +1 -0
  17. package/dist/esm/models/index.js +1 -0
  18. package/dist/models/CommandRequest.d.ts +6 -0
  19. package/dist/models/CommandRequest.js +2 -0
  20. package/dist/models/CommandStreamFrame.d.ts +85 -0
  21. package/dist/models/CommandStreamFrame.js +75 -0
  22. package/dist/models/CreateSandboxRequest.d.ts +6 -0
  23. package/dist/models/CreateSandboxRequest.js +2 -0
  24. package/dist/models/index.d.ts +1 -0
  25. package/dist/models/index.js +1 -0
  26. package/docs/BoatApi.md +4 -3
  27. package/docs/CommandRequest.md +2 -0
  28. package/docs/CommandStreamFrame.md +47 -0
  29. package/docs/CreateSandboxRequest.md +2 -0
  30. package/package.json +1 -1
  31. package/src/apis/BoatApi.ts +7 -2
  32. package/src/boat-helpers.ts +75 -1
  33. package/src/models/CommandRequest.ts +8 -0
  34. package/src/models/CommandStreamFrame.ts +136 -0
  35. package/src/models/CreateSandboxRequest.ts +8 -0
  36. package/src/models/index.ts +1 -0
@@ -25,6 +25,7 @@ docs/CommandRequest.md
25
25
  docs/CommandResponse.md
26
26
  docs/CommandStartedResponse.md
27
27
  docs/CommandStatusResponse.md
28
+ docs/CommandStreamFrame.md
28
29
  docs/CompletionEvent.md
29
30
  docs/Conversation.md
30
31
  docs/ConversationsResponse.md
@@ -163,6 +164,7 @@ src/models/CommandRequest.ts
163
164
  src/models/CommandResponse.ts
164
165
  src/models/CommandStartedResponse.ts
165
166
  src/models/CommandStatusResponse.ts
167
+ src/models/CommandStreamFrame.ts
166
168
  src/models/CompletionEvent.ts
167
169
  src/models/Conversation.ts
168
170
  src/models/ConversationsResponse.ts
@@ -387,12 +387,12 @@ export declare class BoatApi extends runtime.BaseAPI {
387
387
  */
388
388
  commandRequestOpts(input: CommandOperationRequest | runtime.FlatBody<CommandOperationRequest, 'commandRequest'>): Promise<runtime.RequestOpts>;
389
389
  /**
390
- * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. Returns 409 boat_starting (retryable) while the sandbox is still provisioning -- wait until the sandbox state is ready before running commands. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
390
+ * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. With `stream: true` the output arrives as the command writes it, as newline-delimited JSON (`application/x-ndjson`): `{\"type\":\"started\"}`, then `{\"type\":\"stdout\"|\"stderr\",\"data\":\"...\"}` per chunk, and last `{\"type\":\"exit\",...}` (the synchronous result without stdout/stderr) or `{\"type\":\"error\",\"error\":\"...\",\"message\":\"...\"}`. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. A command sent while the sandbox is still starting (right after a resume) waits up to 60s for it to be ready instead of failing; 409 boat_starting (retryable) is returned only if it is still not ready by then. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
391
391
  * Execute a command in a sandbox
392
392
  */
393
393
  commandRaw(requestParameters: CommandOperationRequest | runtime.FlatBody<CommandOperationRequest, 'commandRequest'>, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<Command200Response>>;
394
394
  /**
395
- * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. Returns 409 boat_starting (retryable) while the sandbox is still provisioning -- wait until the sandbox state is ready before running commands. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
395
+ * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. With `stream: true` the output arrives as the command writes it, as newline-delimited JSON (`application/x-ndjson`): `{\"type\":\"started\"}`, then `{\"type\":\"stdout\"|\"stderr\",\"data\":\"...\"}` per chunk, and last `{\"type\":\"exit\",...}` (the synchronous result without stdout/stderr) or `{\"type\":\"error\",\"error\":\"...\",\"message\":\"...\"}`. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. A command sent while the sandbox is still starting (right after a resume) waits up to 60s for it to be ready instead of failing; 409 boat_starting (retryable) is returned only if it is still not ready by then. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
396
396
  * Execute a command in a sandbox
397
397
  */
398
398
  command(requestParameters: CommandOperationRequest | runtime.FlatBody<CommandOperationRequest, 'commandRequest'>, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<Command200Response>;
@@ -331,7 +331,7 @@ class BoatApi extends runtime.BaseAPI {
331
331
  };
332
332
  }
333
333
  /**
334
- * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. Returns 409 boat_starting (retryable) while the sandbox is still provisioning -- wait until the sandbox state is ready before running commands. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
334
+ * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. With `stream: true` the output arrives as the command writes it, as newline-delimited JSON (`application/x-ndjson`): `{\"type\":\"started\"}`, then `{\"type\":\"stdout\"|\"stderr\",\"data\":\"...\"}` per chunk, and last `{\"type\":\"exit\",...}` (the synchronous result without stdout/stderr) or `{\"type\":\"error\",\"error\":\"...\",\"message\":\"...\"}`. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. A command sent while the sandbox is still starting (right after a resume) waits up to 60s for it to be ready instead of failing; 409 boat_starting (retryable) is returned only if it is still not ready by then. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
335
335
  * Execute a command in a sandbox
336
336
  */
337
337
  async commandRaw(requestParameters, initOverrides) {
@@ -340,7 +340,7 @@ class BoatApi extends runtime.BaseAPI {
340
340
  return new runtime.JSONApiResponse(response, (jsonValue) => (0, Command200Response_1.Command200ResponseFromJSON)(jsonValue));
341
341
  }
342
342
  /**
343
- * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. Returns 409 boat_starting (retryable) while the sandbox is still provisioning -- wait until the sandbox state is ready before running commands. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
343
+ * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. With `stream: true` the output arrives as the command writes it, as newline-delimited JSON (`application/x-ndjson`): `{\"type\":\"started\"}`, then `{\"type\":\"stdout\"|\"stderr\",\"data\":\"...\"}` per chunk, and last `{\"type\":\"exit\",...}` (the synchronous result without stdout/stderr) or `{\"type\":\"error\",\"error\":\"...\",\"message\":\"...\"}`. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. A command sent while the sandbox is still starting (right after a resume) waits up to 60s for it to be ready instead of failing; 409 boat_starting (retryable) is returned only if it is still not ready by then. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
344
344
  * Execute a command in a sandbox
345
345
  */
346
346
  async command(requestParameters, initOverrides) {
@@ -1,5 +1,5 @@
1
1
  import { BoatApi } from './apis/BoatApi';
2
- import type { Sandbox, SandboxEvent, DesktopResponse, PromptRequest, PromptRun } from './models';
2
+ import type { Sandbox, SandboxEvent, DesktopResponse, PromptRequest, PromptRun, CommandStreamFrame } from './models';
3
3
  export type WaitOptions = {
4
4
  timeoutMs?: number;
5
5
  intervalMs?: number;
@@ -54,3 +54,19 @@ export declare function stopAndRemove(api: BoatApi, sandboxId: string, options?:
54
54
  export declare function readText(api: BoatApi, sandboxId: string, path: string): Promise<string>;
55
55
  export declare function writeText(api: BoatApi, sandboxId: string, path: string, content: string): Promise<import("./models").FileWriteResponse>;
56
56
  export declare function execCommand(api: BoatApi, sandboxId: string, command: string, cwd?: string, timeoutSeconds?: number): Promise<import("./models").Command200Response>;
57
+ /** One line of a streamed command, as sent (an `exit` frame also carries e.g. `signal`, `oomKilled`). */
58
+ export type CommandFrame = CommandStreamFrame & Record<string, unknown>;
59
+ export type StreamCommandOptions = {
60
+ cwd?: string;
61
+ timeoutSeconds?: number;
62
+ signal?: AbortSignal;
63
+ };
64
+ /**
65
+ * Run a command and yield its output as the command writes it: `started`, then
66
+ * `stdout`/`stderr` chunks (`frame.data`), then exactly one `exit` (`exitCode`,
67
+ * `timedOut`, ...) or `error` (`error`, `message`).
68
+ *
69
+ * Safe to call right after `resume()`, without waiting: the API holds a command
70
+ * sent to a starting sandbox for up to 60 s instead of refusing it.
71
+ */
72
+ export declare function streamCommand(api: BoatApi, sandboxId: string, command: string, options?: StreamCommandOptions): AsyncGenerator<CommandFrame>;
@@ -11,6 +11,7 @@ exports.stopAndRemove = stopAndRemove;
11
11
  exports.readText = readText;
12
12
  exports.writeText = writeText;
13
13
  exports.execCommand = execCommand;
14
+ exports.streamCommand = streamCommand;
14
15
  const terminalPromptStatuses = new Set(['finished', 'failed']);
15
16
  function delay(ms) {
16
17
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -174,3 +175,63 @@ async function writeText(api, sandboxId, path, content) {
174
175
  async function execCommand(api, sandboxId, command, cwd, timeoutSeconds = 30) {
175
176
  return api.command({ sandboxId, commandRequest: { command, cwd, timeoutSeconds } });
176
177
  }
178
+ // A refusal that provably never ran the command (the sandbox is still restoring
179
+ // its disk, `retryable: true` before `started`) is retried for this long.
180
+ const STREAM_RETRY_MS = 60000;
181
+ async function* ndjsonFrames(response) {
182
+ if (!response.body)
183
+ throw new Error('The command stream has no body');
184
+ const reader = response.body.getReader();
185
+ const decoder = new TextDecoder();
186
+ let buffered = '';
187
+ let done = false;
188
+ try {
189
+ while (!done) {
190
+ const chunk = await reader.read();
191
+ done = chunk.done;
192
+ buffered += done ? decoder.decode() : decoder.decode(chunk.value, { stream: true });
193
+ let newline = buffered.indexOf('\n');
194
+ while (newline !== -1) {
195
+ const line = buffered.slice(0, newline).trim();
196
+ buffered = buffered.slice(newline + 1);
197
+ if (line)
198
+ yield JSON.parse(line);
199
+ newline = buffered.indexOf('\n');
200
+ }
201
+ }
202
+ if (buffered.trim())
203
+ yield JSON.parse(buffered);
204
+ }
205
+ finally {
206
+ // The caller stopped early: drop the connection instead of reading the rest.
207
+ if (!done)
208
+ await reader.cancel().catch(() => undefined);
209
+ }
210
+ }
211
+ /**
212
+ * Run a command and yield its output as the command writes it: `started`, then
213
+ * `stdout`/`stderr` chunks (`frame.data`), then exactly one `exit` (`exitCode`,
214
+ * `timedOut`, ...) or `error` (`error`, `message`).
215
+ *
216
+ * Safe to call right after `resume()`, without waiting: the API holds a command
217
+ * sent to a starting sandbox for up to 60 s instead of refusing it.
218
+ */
219
+ async function* streamCommand(api, sandboxId, command, options) {
220
+ const deadline = Date.now() + STREAM_RETRY_MS;
221
+ for (;;) {
222
+ const response = await api.commandRaw({ sandboxId, commandRequest: { command, cwd: options === null || options === void 0 ? void 0 : options.cwd, timeoutSeconds: options === null || options === void 0 ? void 0 : options.timeoutSeconds, stream: true } }, { signal: options === null || options === void 0 ? void 0 : options.signal });
223
+ let started = false;
224
+ let retry = false;
225
+ for await (const frame of ndjsonFrames(response.raw)) {
226
+ started = started || frame.type === 'started';
227
+ if (!started && frame.type === 'error' && frame.retryable === true && Date.now() < deadline) {
228
+ retry = true;
229
+ break;
230
+ }
231
+ yield frame;
232
+ }
233
+ if (!retry)
234
+ return;
235
+ await delay(1000);
236
+ }
237
+ }
@@ -387,12 +387,12 @@ export declare class BoatApi extends runtime.BaseAPI {
387
387
  */
388
388
  commandRequestOpts(input: CommandOperationRequest | runtime.FlatBody<CommandOperationRequest, 'commandRequest'>): Promise<runtime.RequestOpts>;
389
389
  /**
390
- * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. Returns 409 boat_starting (retryable) while the sandbox is still provisioning -- wait until the sandbox state is ready before running commands. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
390
+ * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. With `stream: true` the output arrives as the command writes it, as newline-delimited JSON (`application/x-ndjson`): `{\"type\":\"started\"}`, then `{\"type\":\"stdout\"|\"stderr\",\"data\":\"...\"}` per chunk, and last `{\"type\":\"exit\",...}` (the synchronous result without stdout/stderr) or `{\"type\":\"error\",\"error\":\"...\",\"message\":\"...\"}`. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. A command sent while the sandbox is still starting (right after a resume) waits up to 60s for it to be ready instead of failing; 409 boat_starting (retryable) is returned only if it is still not ready by then. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
391
391
  * Execute a command in a sandbox
392
392
  */
393
393
  commandRaw(requestParameters: CommandOperationRequest | runtime.FlatBody<CommandOperationRequest, 'commandRequest'>, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<Command200Response>>;
394
394
  /**
395
- * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. Returns 409 boat_starting (retryable) while the sandbox is still provisioning -- wait until the sandbox state is ready before running commands. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
395
+ * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. With `stream: true` the output arrives as the command writes it, as newline-delimited JSON (`application/x-ndjson`): `{\"type\":\"started\"}`, then `{\"type\":\"stdout\"|\"stderr\",\"data\":\"...\"}` per chunk, and last `{\"type\":\"exit\",...}` (the synchronous result without stdout/stderr) or `{\"type\":\"error\",\"error\":\"...\",\"message\":\"...\"}`. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. A command sent while the sandbox is still starting (right after a resume) waits up to 60s for it to be ready instead of failing; 409 boat_starting (retryable) is returned only if it is still not ready by then. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
396
396
  * Execute a command in a sandbox
397
397
  */
398
398
  command(requestParameters: CommandOperationRequest | runtime.FlatBody<CommandOperationRequest, 'commandRequest'>, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<Command200Response>;
@@ -295,7 +295,7 @@ export class BoatApi extends runtime.BaseAPI {
295
295
  };
296
296
  }
297
297
  /**
298
- * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. Returns 409 boat_starting (retryable) while the sandbox is still provisioning -- wait until the sandbox state is ready before running commands. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
298
+ * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. With `stream: true` the output arrives as the command writes it, as newline-delimited JSON (`application/x-ndjson`): `{\"type\":\"started\"}`, then `{\"type\":\"stdout\"|\"stderr\",\"data\":\"...\"}` per chunk, and last `{\"type\":\"exit\",...}` (the synchronous result without stdout/stderr) or `{\"type\":\"error\",\"error\":\"...\",\"message\":\"...\"}`. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. A command sent while the sandbox is still starting (right after a resume) waits up to 60s for it to be ready instead of failing; 409 boat_starting (retryable) is returned only if it is still not ready by then. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
299
299
  * Execute a command in a sandbox
300
300
  */
301
301
  async commandRaw(requestParameters, initOverrides) {
@@ -304,7 +304,7 @@ export class BoatApi extends runtime.BaseAPI {
304
304
  return new runtime.JSONApiResponse(response, (jsonValue) => Command200ResponseFromJSON(jsonValue));
305
305
  }
306
306
  /**
307
- * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. Returns 409 boat_starting (retryable) while the sandbox is still provisioning -- wait until the sandbox state is ready before running commands. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
307
+ * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. With `stream: true` the output arrives as the command writes it, as newline-delimited JSON (`application/x-ndjson`): `{\"type\":\"started\"}`, then `{\"type\":\"stdout\"|\"stderr\",\"data\":\"...\"}` per chunk, and last `{\"type\":\"exit\",...}` (the synchronous result without stdout/stderr) or `{\"type\":\"error\",\"error\":\"...\",\"message\":\"...\"}`. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. A command sent while the sandbox is still starting (right after a resume) waits up to 60s for it to be ready instead of failing; 409 boat_starting (retryable) is returned only if it is still not ready by then. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
308
308
  * Execute a command in a sandbox
309
309
  */
310
310
  async command(requestParameters, initOverrides) {
@@ -1,5 +1,5 @@
1
1
  import { BoatApi } from './apis/BoatApi';
2
- import type { Sandbox, SandboxEvent, DesktopResponse, PromptRequest, PromptRun } from './models';
2
+ import type { Sandbox, SandboxEvent, DesktopResponse, PromptRequest, PromptRun, CommandStreamFrame } from './models';
3
3
  export type WaitOptions = {
4
4
  timeoutMs?: number;
5
5
  intervalMs?: number;
@@ -54,3 +54,19 @@ export declare function stopAndRemove(api: BoatApi, sandboxId: string, options?:
54
54
  export declare function readText(api: BoatApi, sandboxId: string, path: string): Promise<string>;
55
55
  export declare function writeText(api: BoatApi, sandboxId: string, path: string, content: string): Promise<import("./models").FileWriteResponse>;
56
56
  export declare function execCommand(api: BoatApi, sandboxId: string, command: string, cwd?: string, timeoutSeconds?: number): Promise<import("./models").Command200Response>;
57
+ /** One line of a streamed command, as sent (an `exit` frame also carries e.g. `signal`, `oomKilled`). */
58
+ export type CommandFrame = CommandStreamFrame & Record<string, unknown>;
59
+ export type StreamCommandOptions = {
60
+ cwd?: string;
61
+ timeoutSeconds?: number;
62
+ signal?: AbortSignal;
63
+ };
64
+ /**
65
+ * Run a command and yield its output as the command writes it: `started`, then
66
+ * `stdout`/`stderr` chunks (`frame.data`), then exactly one `exit` (`exitCode`,
67
+ * `timedOut`, ...) or `error` (`error`, `message`).
68
+ *
69
+ * Safe to call right after `resume()`, without waiting: the API holds a command
70
+ * sent to a starting sandbox for up to 60 s instead of refusing it.
71
+ */
72
+ export declare function streamCommand(api: BoatApi, sandboxId: string, command: string, options?: StreamCommandOptions): AsyncGenerator<CommandFrame>;
@@ -161,3 +161,63 @@ export async function writeText(api, sandboxId, path, content) {
161
161
  export async function execCommand(api, sandboxId, command, cwd, timeoutSeconds = 30) {
162
162
  return api.command({ sandboxId, commandRequest: { command, cwd, timeoutSeconds } });
163
163
  }
164
+ // A refusal that provably never ran the command (the sandbox is still restoring
165
+ // its disk, `retryable: true` before `started`) is retried for this long.
166
+ const STREAM_RETRY_MS = 60000;
167
+ async function* ndjsonFrames(response) {
168
+ if (!response.body)
169
+ throw new Error('The command stream has no body');
170
+ const reader = response.body.getReader();
171
+ const decoder = new TextDecoder();
172
+ let buffered = '';
173
+ let done = false;
174
+ try {
175
+ while (!done) {
176
+ const chunk = await reader.read();
177
+ done = chunk.done;
178
+ buffered += done ? decoder.decode() : decoder.decode(chunk.value, { stream: true });
179
+ let newline = buffered.indexOf('\n');
180
+ while (newline !== -1) {
181
+ const line = buffered.slice(0, newline).trim();
182
+ buffered = buffered.slice(newline + 1);
183
+ if (line)
184
+ yield JSON.parse(line);
185
+ newline = buffered.indexOf('\n');
186
+ }
187
+ }
188
+ if (buffered.trim())
189
+ yield JSON.parse(buffered);
190
+ }
191
+ finally {
192
+ // The caller stopped early: drop the connection instead of reading the rest.
193
+ if (!done)
194
+ await reader.cancel().catch(() => undefined);
195
+ }
196
+ }
197
+ /**
198
+ * Run a command and yield its output as the command writes it: `started`, then
199
+ * `stdout`/`stderr` chunks (`frame.data`), then exactly one `exit` (`exitCode`,
200
+ * `timedOut`, ...) or `error` (`error`, `message`).
201
+ *
202
+ * Safe to call right after `resume()`, without waiting: the API holds a command
203
+ * sent to a starting sandbox for up to 60 s instead of refusing it.
204
+ */
205
+ export async function* streamCommand(api, sandboxId, command, options) {
206
+ const deadline = Date.now() + STREAM_RETRY_MS;
207
+ for (;;) {
208
+ const response = await api.commandRaw({ sandboxId, commandRequest: { command, cwd: options === null || options === void 0 ? void 0 : options.cwd, timeoutSeconds: options === null || options === void 0 ? void 0 : options.timeoutSeconds, stream: true } }, { signal: options === null || options === void 0 ? void 0 : options.signal });
209
+ let started = false;
210
+ let retry = false;
211
+ for await (const frame of ndjsonFrames(response.raw)) {
212
+ started = started || frame.type === 'started';
213
+ if (!started && frame.type === 'error' && frame.retryable === true && Date.now() < deadline) {
214
+ retry = true;
215
+ break;
216
+ }
217
+ yield frame;
218
+ }
219
+ if (!retry)
220
+ return;
221
+ await delay(1000);
222
+ }
223
+ }
@@ -39,6 +39,12 @@ export interface CommandRequest {
39
39
  * @memberof CommandRequest
40
40
  */
41
41
  detached?: boolean;
42
+ /**
43
+ * Stream the output as the command writes it: the response is newline-delimited JSON (application/x-ndjson), one CommandStreamFrame per line. Ignored with detached.
44
+ * @type {boolean}
45
+ * @memberof CommandRequest
46
+ */
47
+ stream?: boolean;
42
48
  }
43
49
  /**
44
50
  * Check if a given object implements the CommandRequest interface.
@@ -31,6 +31,7 @@ export function CommandRequestFromJSONTyped(json, ignoreDiscriminator) {
31
31
  'cwd': json['cwd'] == null ? undefined : json['cwd'],
32
32
  'timeoutSeconds': json['timeoutSeconds'] == null ? undefined : json['timeoutSeconds'],
33
33
  'detached': json['detached'] == null ? undefined : json['detached'],
34
+ 'stream': json['stream'] == null ? undefined : json['stream'],
34
35
  };
35
36
  }
36
37
  export function CommandRequestToJSON(json) {
@@ -45,5 +46,6 @@ export function CommandRequestToJSONTyped(value, ignoreDiscriminator = false) {
45
46
  'cwd': value['cwd'],
46
47
  'timeoutSeconds': value['timeoutSeconds'],
47
48
  'detached': value['detached'],
49
+ 'stream': value['stream'],
48
50
  };
49
51
  }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Boat Public API v1
3
+ * Public JSON API for creating, operating, prompting, observing, and exposing sandboxes from backend services, CI jobs, hosted workers, and Boat automation products. The v1 reference intentionally documents the developer integration surface only. Dashboard billing actions are not part of v1.
4
+ *
5
+ * The version of the OpenAPI document: 1.0.0
6
+ *
7
+ *
8
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
9
+ * https://openapi-generator.tech
10
+ * Do not edit the class manually.
11
+ */
12
+ /**
13
+ * One line of a streamed command. `started` first, then `stdout`/`stderr` chunks, then exactly one `exit` (the synchronous result, without stdout/stderr) or `error`.
14
+ * @export
15
+ * @interface CommandStreamFrame
16
+ */
17
+ export interface CommandStreamFrame {
18
+ /**
19
+ *
20
+ * @type {CommandStreamFrameTypeEnum}
21
+ * @memberof CommandStreamFrame
22
+ */
23
+ type: CommandStreamFrameTypeEnum;
24
+ /**
25
+ * stdout/stderr: the chunk of output, UTF-8.
26
+ * @type {string}
27
+ * @memberof CommandStreamFrame
28
+ */
29
+ data?: string;
30
+ /**
31
+ *
32
+ * @type {number}
33
+ * @memberof CommandStreamFrame
34
+ */
35
+ exitCode?: number | null;
36
+ /**
37
+ *
38
+ * @type {boolean}
39
+ * @memberof CommandStreamFrame
40
+ */
41
+ success?: boolean;
42
+ /**
43
+ *
44
+ * @type {boolean}
45
+ * @memberof CommandStreamFrame
46
+ */
47
+ timedOut?: boolean;
48
+ /**
49
+ *
50
+ * @type {string}
51
+ * @memberof CommandStreamFrame
52
+ */
53
+ error?: string;
54
+ /**
55
+ *
56
+ * @type {string}
57
+ * @memberof CommandStreamFrame
58
+ */
59
+ message?: string;
60
+ /**
61
+ * error: true when the command provably never ran (the sandbox is still restoring its disk), so sending it again is safe.
62
+ * @type {boolean}
63
+ * @memberof CommandStreamFrame
64
+ */
65
+ retryable?: boolean;
66
+ }
67
+ /**
68
+ * @export
69
+ */
70
+ export declare const CommandStreamFrameTypeEnum: {
71
+ readonly Started: 'started';
72
+ readonly Stdout: 'stdout';
73
+ readonly Stderr: 'stderr';
74
+ readonly Exit: 'exit';
75
+ readonly Error: 'error';
76
+ };
77
+ export type CommandStreamFrameTypeEnum = typeof CommandStreamFrameTypeEnum[keyof typeof CommandStreamFrameTypeEnum];
78
+ /**
79
+ * Check if a given object implements the CommandStreamFrame interface.
80
+ */
81
+ export declare function instanceOfCommandStreamFrame(value: object): value is CommandStreamFrame;
82
+ export declare function CommandStreamFrameFromJSON(json: any): CommandStreamFrame;
83
+ export declare function CommandStreamFrameFromJSONTyped(json: any, ignoreDiscriminator: boolean): CommandStreamFrame;
84
+ export declare function CommandStreamFrameToJSON(json: any): CommandStreamFrame;
85
+ export declare function CommandStreamFrameToJSONTyped(value?: CommandStreamFrame | null, ignoreDiscriminator?: boolean): any;
@@ -0,0 +1,67 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /**
4
+ * Boat Public API v1
5
+ * Public JSON API for creating, operating, prompting, observing, and exposing sandboxes from backend services, CI jobs, hosted workers, and Boat automation products. The v1 reference intentionally documents the developer integration surface only. Dashboard billing actions are not part of v1.
6
+ *
7
+ * The version of the OpenAPI document: 1.0.0
8
+ *
9
+ *
10
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
11
+ * https://openapi-generator.tech
12
+ * Do not edit the class manually.
13
+ */
14
+ /**
15
+ * @export
16
+ */
17
+ export const CommandStreamFrameTypeEnum = {
18
+ Started: 'started',
19
+ Stdout: 'stdout',
20
+ Stderr: 'stderr',
21
+ Exit: 'exit',
22
+ Error: 'error'
23
+ };
24
+ /**
25
+ * Check if a given object implements the CommandStreamFrame interface.
26
+ */
27
+ export function instanceOfCommandStreamFrame(value) {
28
+ if (!('type' in value) || value['type'] === undefined)
29
+ return false;
30
+ return true;
31
+ }
32
+ export function CommandStreamFrameFromJSON(json) {
33
+ return CommandStreamFrameFromJSONTyped(json, false);
34
+ }
35
+ export function CommandStreamFrameFromJSONTyped(json, ignoreDiscriminator) {
36
+ if (json == null) {
37
+ return json;
38
+ }
39
+ return {
40
+ 'type': json['type'],
41
+ 'data': json['data'] == null ? undefined : json['data'],
42
+ 'exitCode': json['exitCode'] == null ? undefined : json['exitCode'],
43
+ 'success': json['success'] == null ? undefined : json['success'],
44
+ 'timedOut': json['timedOut'] == null ? undefined : json['timedOut'],
45
+ 'error': json['error'] == null ? undefined : json['error'],
46
+ 'message': json['message'] == null ? undefined : json['message'],
47
+ 'retryable': json['retryable'] == null ? undefined : json['retryable'],
48
+ };
49
+ }
50
+ export function CommandStreamFrameToJSON(json) {
51
+ return CommandStreamFrameToJSONTyped(json, false);
52
+ }
53
+ export function CommandStreamFrameToJSONTyped(value, ignoreDiscriminator = false) {
54
+ if (value == null) {
55
+ return value;
56
+ }
57
+ return {
58
+ 'type': value['type'],
59
+ 'data': value['data'],
60
+ 'exitCode': value['exitCode'],
61
+ 'success': value['success'],
62
+ 'timedOut': value['timedOut'],
63
+ 'error': value['error'],
64
+ 'message': value['message'],
65
+ 'retryable': value['retryable'],
66
+ };
67
+ }
@@ -53,6 +53,12 @@ export interface CreateSandboxRequest {
53
53
  * @memberof CreateSandboxRequest
54
54
  */
55
55
  snapshots?: boolean;
56
+ /**
57
+ * Pass `true` to get a sandbox only if a machine of this type is ready right now. The call answers within about 1.5 s: either the usual `202` with the sandbox, or `503` `no_ready_machine` with nothing created, billed, or counted against your start limits, so you can retry or fall back at once. Without it, a create waits for a machine to be built when none is ready. Not combinable with `from`.
58
+ * @type {boolean}
59
+ * @memberof CreateSandboxRequest
60
+ */
61
+ failFast?: boolean;
56
62
  /**
57
63
  * Shell script that runs on the sandbox after it is ready. Ready means "ready to accept the user", not "setup done": the script starts in the background once provisioning completes and never blocks the sandbox becoming usable. It runs as the sandbox user via `bash`, with the sandbox's environment applied, and its output goes to a log file on the sandbox. Observe the outcome as `setupStatus` (pending/running/done/failed) and `setupError` on the sandbox. Rejected with a 400 `invalid_setup_script` error when it is not a string or exceeds 64KB.
58
64
  * @type {string}
@@ -39,6 +39,7 @@ export function CreateSandboxRequestFromJSONTyped(json, ignoreDiscriminator) {
39
39
  'environment': json['environment'] == null ? undefined : json['environment'],
40
40
  'noEnv': json['noEnv'] == null ? undefined : json['noEnv'],
41
41
  'snapshots': json['snapshots'] == null ? undefined : json['snapshots'],
42
+ 'failFast': json['failFast'] == null ? undefined : json['failFast'],
42
43
  'setupScript': json['setupScript'] == null ? undefined : json['setupScript'],
43
44
  'org': json['org'] == null ? undefined : json['org'],
44
45
  'teamId': json['teamId'] == null ? undefined : json['teamId'],
@@ -59,6 +60,7 @@ export function CreateSandboxRequestToJSONTyped(value, ignoreDiscriminator = fal
59
60
  'environment': value['environment'],
60
61
  'noEnv': value['noEnv'],
61
62
  'snapshots': value['snapshots'],
63
+ 'failFast': value['failFast'],
62
64
  'setupScript': value['setupScript'],
63
65
  'org': value['org'],
64
66
  'teamId': value['teamId'],
@@ -20,6 +20,7 @@ export * from './CommandRequest';
20
20
  export * from './CommandResponse';
21
21
  export * from './CommandStartedResponse';
22
22
  export * from './CommandStatusResponse';
23
+ export * from './CommandStreamFrame';
23
24
  export * from './CompletionEvent';
24
25
  export * from './Conversation';
25
26
  export * from './ConversationsResponse';
@@ -22,6 +22,7 @@ export * from './CommandRequest';
22
22
  export * from './CommandResponse';
23
23
  export * from './CommandStartedResponse';
24
24
  export * from './CommandStatusResponse';
25
+ export * from './CommandStreamFrame';
25
26
  export * from './CompletionEvent';
26
27
  export * from './Conversation';
27
28
  export * from './ConversationsResponse';
@@ -39,6 +39,12 @@ export interface CommandRequest {
39
39
  * @memberof CommandRequest
40
40
  */
41
41
  detached?: boolean;
42
+ /**
43
+ * Stream the output as the command writes it: the response is newline-delimited JSON (application/x-ndjson), one CommandStreamFrame per line. Ignored with detached.
44
+ * @type {boolean}
45
+ * @memberof CommandRequest
46
+ */
47
+ stream?: boolean;
42
48
  }
43
49
  /**
44
50
  * Check if a given object implements the CommandRequest interface.
@@ -38,6 +38,7 @@ function CommandRequestFromJSONTyped(json, ignoreDiscriminator) {
38
38
  'cwd': json['cwd'] == null ? undefined : json['cwd'],
39
39
  'timeoutSeconds': json['timeoutSeconds'] == null ? undefined : json['timeoutSeconds'],
40
40
  'detached': json['detached'] == null ? undefined : json['detached'],
41
+ 'stream': json['stream'] == null ? undefined : json['stream'],
41
42
  };
42
43
  }
43
44
  function CommandRequestToJSON(json) {
@@ -52,5 +53,6 @@ function CommandRequestToJSONTyped(value, ignoreDiscriminator = false) {
52
53
  'cwd': value['cwd'],
53
54
  'timeoutSeconds': value['timeoutSeconds'],
54
55
  'detached': value['detached'],
56
+ 'stream': value['stream'],
55
57
  };
56
58
  }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Boat Public API v1
3
+ * Public JSON API for creating, operating, prompting, observing, and exposing sandboxes from backend services, CI jobs, hosted workers, and Boat automation products. The v1 reference intentionally documents the developer integration surface only. Dashboard billing actions are not part of v1.
4
+ *
5
+ * The version of the OpenAPI document: 1.0.0
6
+ *
7
+ *
8
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
9
+ * https://openapi-generator.tech
10
+ * Do not edit the class manually.
11
+ */
12
+ /**
13
+ * One line of a streamed command. `started` first, then `stdout`/`stderr` chunks, then exactly one `exit` (the synchronous result, without stdout/stderr) or `error`.
14
+ * @export
15
+ * @interface CommandStreamFrame
16
+ */
17
+ export interface CommandStreamFrame {
18
+ /**
19
+ *
20
+ * @type {CommandStreamFrameTypeEnum}
21
+ * @memberof CommandStreamFrame
22
+ */
23
+ type: CommandStreamFrameTypeEnum;
24
+ /**
25
+ * stdout/stderr: the chunk of output, UTF-8.
26
+ * @type {string}
27
+ * @memberof CommandStreamFrame
28
+ */
29
+ data?: string;
30
+ /**
31
+ *
32
+ * @type {number}
33
+ * @memberof CommandStreamFrame
34
+ */
35
+ exitCode?: number | null;
36
+ /**
37
+ *
38
+ * @type {boolean}
39
+ * @memberof CommandStreamFrame
40
+ */
41
+ success?: boolean;
42
+ /**
43
+ *
44
+ * @type {boolean}
45
+ * @memberof CommandStreamFrame
46
+ */
47
+ timedOut?: boolean;
48
+ /**
49
+ *
50
+ * @type {string}
51
+ * @memberof CommandStreamFrame
52
+ */
53
+ error?: string;
54
+ /**
55
+ *
56
+ * @type {string}
57
+ * @memberof CommandStreamFrame
58
+ */
59
+ message?: string;
60
+ /**
61
+ * error: true when the command provably never ran (the sandbox is still restoring its disk), so sending it again is safe.
62
+ * @type {boolean}
63
+ * @memberof CommandStreamFrame
64
+ */
65
+ retryable?: boolean;
66
+ }
67
+ /**
68
+ * @export
69
+ */
70
+ export declare const CommandStreamFrameTypeEnum: {
71
+ readonly Started: 'started';
72
+ readonly Stdout: 'stdout';
73
+ readonly Stderr: 'stderr';
74
+ readonly Exit: 'exit';
75
+ readonly Error: 'error';
76
+ };
77
+ export type CommandStreamFrameTypeEnum = typeof CommandStreamFrameTypeEnum[keyof typeof CommandStreamFrameTypeEnum];
78
+ /**
79
+ * Check if a given object implements the CommandStreamFrame interface.
80
+ */
81
+ export declare function instanceOfCommandStreamFrame(value: object): value is CommandStreamFrame;
82
+ export declare function CommandStreamFrameFromJSON(json: any): CommandStreamFrame;
83
+ export declare function CommandStreamFrameFromJSONTyped(json: any, ignoreDiscriminator: boolean): CommandStreamFrame;
84
+ export declare function CommandStreamFrameToJSON(json: any): CommandStreamFrame;
85
+ export declare function CommandStreamFrameToJSONTyped(value?: CommandStreamFrame | null, ignoreDiscriminator?: boolean): any;
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ /* tslint:disable */
3
+ /* eslint-disable */
4
+ /**
5
+ * Boat Public API v1
6
+ * Public JSON API for creating, operating, prompting, observing, and exposing sandboxes from backend services, CI jobs, hosted workers, and Boat automation products. The v1 reference intentionally documents the developer integration surface only. Dashboard billing actions are not part of v1.
7
+ *
8
+ * The version of the OpenAPI document: 1.0.0
9
+ *
10
+ *
11
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
12
+ * https://openapi-generator.tech
13
+ * Do not edit the class manually.
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.CommandStreamFrameTypeEnum = void 0;
17
+ exports.instanceOfCommandStreamFrame = instanceOfCommandStreamFrame;
18
+ exports.CommandStreamFrameFromJSON = CommandStreamFrameFromJSON;
19
+ exports.CommandStreamFrameFromJSONTyped = CommandStreamFrameFromJSONTyped;
20
+ exports.CommandStreamFrameToJSON = CommandStreamFrameToJSON;
21
+ exports.CommandStreamFrameToJSONTyped = CommandStreamFrameToJSONTyped;
22
+ /**
23
+ * @export
24
+ */
25
+ exports.CommandStreamFrameTypeEnum = {
26
+ Started: 'started',
27
+ Stdout: 'stdout',
28
+ Stderr: 'stderr',
29
+ Exit: 'exit',
30
+ Error: 'error'
31
+ };
32
+ /**
33
+ * Check if a given object implements the CommandStreamFrame interface.
34
+ */
35
+ function instanceOfCommandStreamFrame(value) {
36
+ if (!('type' in value) || value['type'] === undefined)
37
+ return false;
38
+ return true;
39
+ }
40
+ function CommandStreamFrameFromJSON(json) {
41
+ return CommandStreamFrameFromJSONTyped(json, false);
42
+ }
43
+ function CommandStreamFrameFromJSONTyped(json, ignoreDiscriminator) {
44
+ if (json == null) {
45
+ return json;
46
+ }
47
+ return {
48
+ 'type': json['type'],
49
+ 'data': json['data'] == null ? undefined : json['data'],
50
+ 'exitCode': json['exitCode'] == null ? undefined : json['exitCode'],
51
+ 'success': json['success'] == null ? undefined : json['success'],
52
+ 'timedOut': json['timedOut'] == null ? undefined : json['timedOut'],
53
+ 'error': json['error'] == null ? undefined : json['error'],
54
+ 'message': json['message'] == null ? undefined : json['message'],
55
+ 'retryable': json['retryable'] == null ? undefined : json['retryable'],
56
+ };
57
+ }
58
+ function CommandStreamFrameToJSON(json) {
59
+ return CommandStreamFrameToJSONTyped(json, false);
60
+ }
61
+ function CommandStreamFrameToJSONTyped(value, ignoreDiscriminator = false) {
62
+ if (value == null) {
63
+ return value;
64
+ }
65
+ return {
66
+ 'type': value['type'],
67
+ 'data': value['data'],
68
+ 'exitCode': value['exitCode'],
69
+ 'success': value['success'],
70
+ 'timedOut': value['timedOut'],
71
+ 'error': value['error'],
72
+ 'message': value['message'],
73
+ 'retryable': value['retryable'],
74
+ };
75
+ }
@@ -53,6 +53,12 @@ export interface CreateSandboxRequest {
53
53
  * @memberof CreateSandboxRequest
54
54
  */
55
55
  snapshots?: boolean;
56
+ /**
57
+ * Pass `true` to get a sandbox only if a machine of this type is ready right now. The call answers within about 1.5 s: either the usual `202` with the sandbox, or `503` `no_ready_machine` with nothing created, billed, or counted against your start limits, so you can retry or fall back at once. Without it, a create waits for a machine to be built when none is ready. Not combinable with `from`.
58
+ * @type {boolean}
59
+ * @memberof CreateSandboxRequest
60
+ */
61
+ failFast?: boolean;
56
62
  /**
57
63
  * Shell script that runs on the sandbox after it is ready. Ready means "ready to accept the user", not "setup done": the script starts in the background once provisioning completes and never blocks the sandbox becoming usable. It runs as the sandbox user via `bash`, with the sandbox's environment applied, and its output goes to a log file on the sandbox. Observe the outcome as `setupStatus` (pending/running/done/failed) and `setupError` on the sandbox. Rejected with a 400 `invalid_setup_script` error when it is not a string or exceeds 64KB.
58
64
  * @type {string}
@@ -47,6 +47,7 @@ function CreateSandboxRequestFromJSONTyped(json, ignoreDiscriminator) {
47
47
  'environment': json['environment'] == null ? undefined : json['environment'],
48
48
  'noEnv': json['noEnv'] == null ? undefined : json['noEnv'],
49
49
  'snapshots': json['snapshots'] == null ? undefined : json['snapshots'],
50
+ 'failFast': json['failFast'] == null ? undefined : json['failFast'],
50
51
  'setupScript': json['setupScript'] == null ? undefined : json['setupScript'],
51
52
  'org': json['org'] == null ? undefined : json['org'],
52
53
  'teamId': json['teamId'] == null ? undefined : json['teamId'],
@@ -67,6 +68,7 @@ function CreateSandboxRequestToJSONTyped(value, ignoreDiscriminator = false) {
67
68
  'environment': value['environment'],
68
69
  'noEnv': value['noEnv'],
69
70
  'snapshots': value['snapshots'],
71
+ 'failFast': value['failFast'],
70
72
  'setupScript': value['setupScript'],
71
73
  'org': value['org'],
72
74
  'teamId': value['teamId'],
@@ -20,6 +20,7 @@ export * from './CommandRequest';
20
20
  export * from './CommandResponse';
21
21
  export * from './CommandStartedResponse';
22
22
  export * from './CommandStatusResponse';
23
+ export * from './CommandStreamFrame';
23
24
  export * from './CompletionEvent';
24
25
  export * from './Conversation';
25
26
  export * from './ConversationsResponse';
@@ -38,6 +38,7 @@ __exportStar(require("./CommandRequest"), exports);
38
38
  __exportStar(require("./CommandResponse"), exports);
39
39
  __exportStar(require("./CommandStartedResponse"), exports);
40
40
  __exportStar(require("./CommandStatusResponse"), exports);
41
+ __exportStar(require("./CommandStreamFrame"), exports);
41
42
  __exportStar(require("./CompletionEvent"), exports);
42
43
  __exportStar(require("./Conversation"), exports);
43
44
  __exportStar(require("./ConversationsResponse"), exports);
package/docs/BoatApi.md CHANGED
@@ -368,7 +368,7 @@ example().catch(console.error);
368
368
 
369
369
  Execute a command in a sandbox
370
370
 
371
- Runs the command synchronously by default (timeout configurable via &#x60;timeoutSeconds&#x60;, 600s cap). With &#x60;detached: true&#x60; the command starts in the background and a process id is returned immediately; poll &#x60;/sandboxes/{sandboxId}/commands/{processId}&#x60; for status and logs. Returns 400 invalid_timeout when &#x60;timeoutSeconds&#x60; is not an integer in 1-600. Returns 409 boat_starting (retryable) while the sandbox is still provisioning -- wait until the sandbox state is ready before running commands. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
371
+ Runs the command synchronously by default (timeout configurable via &#x60;timeoutSeconds&#x60;, 600s cap). With &#x60;detached: true&#x60; the command starts in the background and a process id is returned immediately; poll &#x60;/sandboxes/{sandboxId}/commands/{processId}&#x60; for status and logs. With &#x60;stream: true&#x60; the output arrives as the command writes it, as newline-delimited JSON (&#x60;application/x-ndjson&#x60;): &#x60;{\&quot;type\&quot;:\&quot;started\&quot;}&#x60;, then &#x60;{\&quot;type\&quot;:\&quot;stdout\&quot;|\&quot;stderr\&quot;,\&quot;data\&quot;:\&quot;...\&quot;}&#x60; per chunk, and last &#x60;{\&quot;type\&quot;:\&quot;exit\&quot;,...}&#x60; (the synchronous result without stdout/stderr) or &#x60;{\&quot;type\&quot;:\&quot;error\&quot;,\&quot;error\&quot;:\&quot;...\&quot;,\&quot;message\&quot;:\&quot;...\&quot;}&#x60;. Returns 400 invalid_timeout when &#x60;timeoutSeconds&#x60; is not an integer in 1-600. A command sent while the sandbox is still starting (right after a resume) waits up to 60s for it to be ready instead of failing; 409 boat_starting (retryable) is returned only if it is still not ready by then. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
372
372
 
373
373
  ### Example
374
374
 
@@ -425,13 +425,13 @@ example().catch(console.error);
425
425
  ### HTTP request headers
426
426
 
427
427
  - **Content-Type**: `application/json`
428
- - **Accept**: `application/json`
428
+ - **Accept**: `application/json`, `application/x-ndjson`
429
429
 
430
430
 
431
431
  ### HTTP response details
432
432
  | Status code | Description | Response headers |
433
433
  |-------------|-------------|------------------|
434
- | **200** | Command result (synchronous) or process start confirmation (detached). | - |
434
+ | **200** | Command result (synchronous), process start confirmation (detached), or the output stream (&#x60;stream: true&#x60;). | - |
435
435
  | **400** | Invalid request body or parameters. | - |
436
436
  | **401** | Missing or invalid bearer token. | - |
437
437
  | **404** | Resource not found. | - |
@@ -672,6 +672,7 @@ example().catch(console.error);
672
672
  | **402** | Account cannot currently create or operate sandboxes. The error body may include a dashboard billing URL, but billing actions are not part of the v1 API. | - |
673
673
  | **409** | Request conflicts with current account or sandbox state. | - |
674
674
  | **429** | Machine start or concurrent-sandbox limit reached. Create, fork and resume each count as one machine start against your plan\&#39;s start limits (see the Billing guide; &#x60;rate_limited&#x60;, naming the window you hit). A sandbox that would exceed your plan\&#39;s concurrent-sandbox cap is refused with &#x60;limit_reached&#x60;, or &#x60;member_limit_reached&#x60; when an organization owner has capped you below the plan. | - |
675
+ | **503** | No capacity. &#x60;no_ready_machine&#x60;: a &#x60;failFast&#x60; create found no ready machine of that type; nothing was created, billed, or counted. &#x60;out_of_capacity&#x60;: creates are paused until the provisioning queue drains. | - |
675
676
 
676
677
  [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md)
677
678
 
@@ -10,6 +10,7 @@ Name | Type
10
10
  `cwd` | string
11
11
  `timeoutSeconds` | number
12
12
  `detached` | boolean
13
+ `stream` | boolean
13
14
 
14
15
  ## Example
15
16
 
@@ -22,6 +23,7 @@ const example = {
22
23
  "cwd": null,
23
24
  "timeoutSeconds": null,
24
25
  "detached": null,
26
+ "stream": null,
25
27
  } satisfies CommandRequest
26
28
 
27
29
  console.log(example)
@@ -0,0 +1,47 @@
1
+
2
+ # CommandStreamFrame
3
+
4
+ One line of a streamed command. `started` first, then `stdout`/`stderr` chunks, then exactly one `exit` (the synchronous result, without stdout/stderr) or `error`.
5
+
6
+ ## Properties
7
+
8
+ Name | Type
9
+ ------------ | -------------
10
+ `type` | string
11
+ `data` | string
12
+ `exitCode` | number
13
+ `success` | boolean
14
+ `timedOut` | boolean
15
+ `error` | string
16
+ `message` | string
17
+ `retryable` | boolean
18
+
19
+ ## Example
20
+
21
+ ```typescript
22
+ import type { CommandStreamFrame } from '@boatdev/sdk'
23
+
24
+ // TODO: Update the object below with actual values
25
+ const example = {
26
+ "type": null,
27
+ "data": null,
28
+ "exitCode": null,
29
+ "success": null,
30
+ "timedOut": null,
31
+ "error": null,
32
+ "message": null,
33
+ "retryable": null,
34
+ } satisfies CommandStreamFrame
35
+
36
+ console.log(example)
37
+
38
+ // Convert the instance to a JSON string
39
+ const exampleJSON: string = JSON.stringify(example)
40
+ console.log(exampleJSON)
41
+
42
+ // Parse the JSON string back to an object
43
+ const exampleParsed = JSON.parse(exampleJSON) as CommandStreamFrame
44
+ console.log(exampleParsed)
45
+ ```
46
+
47
+ [[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md)
@@ -13,6 +13,7 @@ Name | Type
13
13
  `environment` | string
14
14
  `noEnv` | boolean
15
15
  `snapshots` | boolean
16
+ `failFast` | boolean
16
17
  `setupScript` | string
17
18
  `org` | string
18
19
  `teamId` | string
@@ -31,6 +32,7 @@ const example = {
31
32
  "environment": null,
32
33
  "noEnv": null,
33
34
  "snapshots": null,
35
+ "failFast": null,
34
36
  "setupScript": null,
35
37
  "org": null,
36
38
  "teamId": null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boatdev/sdk",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "OpenAPI client for @boatdev/sdk",
5
5
  "author": "OpenAPI-Generator",
6
6
  "license": "MIT",
@@ -63,6 +63,11 @@ import {
63
63
  CommandStatusResponseFromJSON,
64
64
  CommandStatusResponseToJSON,
65
65
  } from '../models/CommandStatusResponse';
66
+ import {
67
+ type CommandStreamFrame,
68
+ CommandStreamFrameFromJSON,
69
+ CommandStreamFrameToJSON,
70
+ } from '../models/CommandStreamFrame';
66
71
  import {
67
72
  type ConversationsResponse,
68
73
  ConversationsResponseFromJSON,
@@ -979,7 +984,7 @@ export class BoatApi extends runtime.BaseAPI {
979
984
  }
980
985
 
981
986
  /**
982
- * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. Returns 409 boat_starting (retryable) while the sandbox is still provisioning -- wait until the sandbox state is ready before running commands. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
987
+ * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. With `stream: true` the output arrives as the command writes it, as newline-delimited JSON (`application/x-ndjson`): `{\"type\":\"started\"}`, then `{\"type\":\"stdout\"|\"stderr\",\"data\":\"...\"}` per chunk, and last `{\"type\":\"exit\",...}` (the synchronous result without stdout/stderr) or `{\"type\":\"error\",\"error\":\"...\",\"message\":\"...\"}`. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. A command sent while the sandbox is still starting (right after a resume) waits up to 60s for it to be ready instead of failing; 409 boat_starting (retryable) is returned only if it is still not ready by then. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
983
988
  * Execute a command in a sandbox
984
989
  */
985
990
  async commandRaw(requestParameters: CommandOperationRequest | runtime.FlatBody<CommandOperationRequest, 'commandRequest'>, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<Command200Response>> {
@@ -990,7 +995,7 @@ export class BoatApi extends runtime.BaseAPI {
990
995
  }
991
996
 
992
997
  /**
993
- * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. Returns 409 boat_starting (retryable) while the sandbox is still provisioning -- wait until the sandbox state is ready before running commands. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
998
+ * Runs the command synchronously by default (timeout configurable via `timeoutSeconds`, 600s cap). With `detached: true` the command starts in the background and a process id is returned immediately; poll `/sandboxes/{sandboxId}/commands/{processId}` for status and logs. With `stream: true` the output arrives as the command writes it, as newline-delimited JSON (`application/x-ndjson`): `{\"type\":\"started\"}`, then `{\"type\":\"stdout\"|\"stderr\",\"data\":\"...\"}` per chunk, and last `{\"type\":\"exit\",...}` (the synchronous result without stdout/stderr) or `{\"type\":\"error\",\"error\":\"...\",\"message\":\"...\"}`. Returns 400 invalid_timeout when `timeoutSeconds` is not an integer in 1-600. A command sent while the sandbox is still starting (right after a resume) waits up to 60s for it to be ready instead of failing; 409 boat_starting (retryable) is returned only if it is still not ready by then. Command execution is never retried automatically: a 502 boat_direct_failed means the command may already be running on the sandbox.
994
999
  * Execute a command in a sandbox
995
1000
  */
996
1001
  async command(requestParameters: CommandOperationRequest | runtime.FlatBody<CommandOperationRequest, 'commandRequest'>, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<Command200Response> {
@@ -1,6 +1,6 @@
1
1
 
2
2
  import { BoatApi } from './apis/BoatApi';
3
- import type { Sandbox, SandboxEvent, DesktopResponse, PromptRequest, PromptRun } from './models';
3
+ import type { Sandbox, SandboxEvent, DesktopResponse, PromptRequest, PromptRun, CommandStreamFrame } from './models';
4
4
 
5
5
  export type WaitOptions = {
6
6
  timeoutMs?: number;
@@ -185,3 +185,77 @@ export async function writeText(api: BoatApi, sandboxId: string, path: string, c
185
185
  export async function execCommand(api: BoatApi, sandboxId: string, command: string, cwd?: string, timeoutSeconds = 30) {
186
186
  return api.command({ sandboxId, commandRequest: { command, cwd, timeoutSeconds } });
187
187
  }
188
+
189
+ /** One line of a streamed command, as sent (an `exit` frame also carries e.g. `signal`, `oomKilled`). */
190
+ export type CommandFrame = CommandStreamFrame & Record<string, unknown>;
191
+
192
+ export type StreamCommandOptions = {
193
+ cwd?: string;
194
+ timeoutSeconds?: number;
195
+ signal?: AbortSignal;
196
+ };
197
+
198
+ // A refusal that provably never ran the command (the sandbox is still restoring
199
+ // its disk, `retryable: true` before `started`) is retried for this long.
200
+ const STREAM_RETRY_MS = 60_000;
201
+
202
+ async function* ndjsonFrames(response: Response): AsyncGenerator<CommandFrame> {
203
+ if (!response.body) throw new Error('The command stream has no body');
204
+ const reader = response.body.getReader();
205
+ const decoder = new TextDecoder();
206
+ let buffered = '';
207
+ let done = false;
208
+ try {
209
+ while (!done) {
210
+ const chunk = await reader.read();
211
+ done = chunk.done;
212
+ buffered += done ? decoder.decode() : decoder.decode(chunk.value, { stream: true });
213
+ let newline = buffered.indexOf('\n');
214
+ while (newline !== -1) {
215
+ const line = buffered.slice(0, newline).trim();
216
+ buffered = buffered.slice(newline + 1);
217
+ if (line) yield JSON.parse(line);
218
+ newline = buffered.indexOf('\n');
219
+ }
220
+ }
221
+ if (buffered.trim()) yield JSON.parse(buffered);
222
+ } finally {
223
+ // The caller stopped early: drop the connection instead of reading the rest.
224
+ if (!done) await reader.cancel().catch(() => undefined);
225
+ }
226
+ }
227
+
228
+ /**
229
+ * Run a command and yield its output as the command writes it: `started`, then
230
+ * `stdout`/`stderr` chunks (`frame.data`), then exactly one `exit` (`exitCode`,
231
+ * `timedOut`, ...) or `error` (`error`, `message`).
232
+ *
233
+ * Safe to call right after `resume()`, without waiting: the API holds a command
234
+ * sent to a starting sandbox for up to 60 s instead of refusing it.
235
+ */
236
+ export async function* streamCommand(
237
+ api: BoatApi,
238
+ sandboxId: string,
239
+ command: string,
240
+ options?: StreamCommandOptions,
241
+ ): AsyncGenerator<CommandFrame> {
242
+ const deadline = Date.now() + STREAM_RETRY_MS;
243
+ for (;;) {
244
+ const response = await api.commandRaw(
245
+ { sandboxId, commandRequest: { command, cwd: options?.cwd, timeoutSeconds: options?.timeoutSeconds, stream: true } },
246
+ { signal: options?.signal },
247
+ );
248
+ let started = false;
249
+ let retry = false;
250
+ for await (const frame of ndjsonFrames(response.raw)) {
251
+ started = started || frame.type === 'started';
252
+ if (!started && frame.type === 'error' && frame.retryable === true && Date.now() < deadline) {
253
+ retry = true;
254
+ break;
255
+ }
256
+ yield frame;
257
+ }
258
+ if (!retry) return;
259
+ await delay(1_000);
260
+ }
261
+ }
@@ -43,6 +43,12 @@ export interface CommandRequest {
43
43
  * @memberof CommandRequest
44
44
  */
45
45
  detached?: boolean;
46
+ /**
47
+ * Stream the output as the command writes it: the response is newline-delimited JSON (application/x-ndjson), one CommandStreamFrame per line. Ignored with detached.
48
+ * @type {boolean}
49
+ * @memberof CommandRequest
50
+ */
51
+ stream?: boolean;
46
52
  }
47
53
 
48
54
  /**
@@ -67,6 +73,7 @@ export function CommandRequestFromJSONTyped(json: any, ignoreDiscriminator: bool
67
73
  'cwd': json['cwd'] == null ? undefined : json['cwd'],
68
74
  'timeoutSeconds': json['timeoutSeconds'] == null ? undefined : json['timeoutSeconds'],
69
75
  'detached': json['detached'] == null ? undefined : json['detached'],
76
+ 'stream': json['stream'] == null ? undefined : json['stream'],
70
77
  };
71
78
  }
72
79
 
@@ -85,6 +92,7 @@ export function CommandRequestToJSONTyped(value?: CommandRequest | null, ignoreD
85
92
  'cwd': value['cwd'],
86
93
  'timeoutSeconds': value['timeoutSeconds'],
87
94
  'detached': value['detached'],
95
+ 'stream': value['stream'],
88
96
  };
89
97
  }
90
98
 
@@ -0,0 +1,136 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /**
4
+ * Boat Public API v1
5
+ * Public JSON API for creating, operating, prompting, observing, and exposing sandboxes from backend services, CI jobs, hosted workers, and Boat automation products. The v1 reference intentionally documents the developer integration surface only. Dashboard billing actions are not part of v1.
6
+ *
7
+ * The version of the OpenAPI document: 1.0.0
8
+ *
9
+ *
10
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
11
+ * https://openapi-generator.tech
12
+ * Do not edit the class manually.
13
+ */
14
+
15
+ import { mapValues } from '../runtime';
16
+ /**
17
+ * One line of a streamed command. `started` first, then `stdout`/`stderr` chunks, then exactly one `exit` (the synchronous result, without stdout/stderr) or `error`.
18
+ * @export
19
+ * @interface CommandStreamFrame
20
+ */
21
+ export interface CommandStreamFrame {
22
+ /**
23
+ *
24
+ * @type {CommandStreamFrameTypeEnum}
25
+ * @memberof CommandStreamFrame
26
+ */
27
+ type: CommandStreamFrameTypeEnum;
28
+ /**
29
+ * stdout/stderr: the chunk of output, UTF-8.
30
+ * @type {string}
31
+ * @memberof CommandStreamFrame
32
+ */
33
+ data?: string;
34
+ /**
35
+ *
36
+ * @type {number}
37
+ * @memberof CommandStreamFrame
38
+ */
39
+ exitCode?: number | null;
40
+ /**
41
+ *
42
+ * @type {boolean}
43
+ * @memberof CommandStreamFrame
44
+ */
45
+ success?: boolean;
46
+ /**
47
+ *
48
+ * @type {boolean}
49
+ * @memberof CommandStreamFrame
50
+ */
51
+ timedOut?: boolean;
52
+ /**
53
+ *
54
+ * @type {string}
55
+ * @memberof CommandStreamFrame
56
+ */
57
+ error?: string;
58
+ /**
59
+ *
60
+ * @type {string}
61
+ * @memberof CommandStreamFrame
62
+ */
63
+ message?: string;
64
+ /**
65
+ * error: true when the command provably never ran (the sandbox is still restoring its disk), so sending it again is safe.
66
+ * @type {boolean}
67
+ * @memberof CommandStreamFrame
68
+ */
69
+ retryable?: boolean;
70
+ }
71
+
72
+
73
+ /**
74
+ * @export
75
+ */
76
+ export const CommandStreamFrameTypeEnum = {
77
+ Started: 'started',
78
+ Stdout: 'stdout',
79
+ Stderr: 'stderr',
80
+ Exit: 'exit',
81
+ Error: 'error'
82
+ } as const;
83
+ export type CommandStreamFrameTypeEnum = typeof CommandStreamFrameTypeEnum[keyof typeof CommandStreamFrameTypeEnum];
84
+
85
+
86
+ /**
87
+ * Check if a given object implements the CommandStreamFrame interface.
88
+ */
89
+ export function instanceOfCommandStreamFrame(value: object): value is CommandStreamFrame {
90
+ if (!('type' in value) || value['type'] === undefined) return false;
91
+ return true;
92
+ }
93
+
94
+ export function CommandStreamFrameFromJSON(json: any): CommandStreamFrame {
95
+ return CommandStreamFrameFromJSONTyped(json, false);
96
+ }
97
+
98
+ export function CommandStreamFrameFromJSONTyped(json: any, ignoreDiscriminator: boolean): CommandStreamFrame {
99
+ if (json == null) {
100
+ return json;
101
+ }
102
+ return {
103
+
104
+ 'type': json['type'],
105
+ 'data': json['data'] == null ? undefined : json['data'],
106
+ 'exitCode': json['exitCode'] == null ? undefined : json['exitCode'],
107
+ 'success': json['success'] == null ? undefined : json['success'],
108
+ 'timedOut': json['timedOut'] == null ? undefined : json['timedOut'],
109
+ 'error': json['error'] == null ? undefined : json['error'],
110
+ 'message': json['message'] == null ? undefined : json['message'],
111
+ 'retryable': json['retryable'] == null ? undefined : json['retryable'],
112
+ };
113
+ }
114
+
115
+ export function CommandStreamFrameToJSON(json: any): CommandStreamFrame {
116
+ return CommandStreamFrameToJSONTyped(json, false);
117
+ }
118
+
119
+ export function CommandStreamFrameToJSONTyped(value?: CommandStreamFrame | null, ignoreDiscriminator: boolean = false): any {
120
+ if (value == null) {
121
+ return value;
122
+ }
123
+
124
+ return {
125
+
126
+ 'type': value['type'],
127
+ 'data': value['data'],
128
+ 'exitCode': value['exitCode'],
129
+ 'success': value['success'],
130
+ 'timedOut': value['timedOut'],
131
+ 'error': value['error'],
132
+ 'message': value['message'],
133
+ 'retryable': value['retryable'],
134
+ };
135
+ }
136
+
@@ -55,6 +55,12 @@ export interface CreateSandboxRequest {
55
55
  * @memberof CreateSandboxRequest
56
56
  */
57
57
  snapshots?: boolean;
58
+ /**
59
+ * Pass `true` to get a sandbox only if a machine of this type is ready right now. The call answers within about 1.5 s: either the usual `202` with the sandbox, or `503` `no_ready_machine` with nothing created, billed, or counted against your start limits, so you can retry or fall back at once. Without it, a create waits for a machine to be built when none is ready. Not combinable with `from`.
60
+ * @type {boolean}
61
+ * @memberof CreateSandboxRequest
62
+ */
63
+ failFast?: boolean;
58
64
  /**
59
65
  * Shell script that runs on the sandbox after it is ready. Ready means "ready to accept the user", not "setup done": the script starts in the background once provisioning completes and never blocks the sandbox becoming usable. It runs as the sandbox user via `bash`, with the sandbox's environment applied, and its output goes to a log file on the sandbox. Observe the outcome as `setupStatus` (pending/running/done/failed) and `setupError` on the sandbox. Rejected with a 400 `invalid_setup_script` error when it is not a string or exceeds 64KB.
60
66
  * @type {string}
@@ -116,6 +122,7 @@ export function CreateSandboxRequestFromJSONTyped(json: any, ignoreDiscriminator
116
122
  'environment': json['environment'] == null ? undefined : json['environment'],
117
123
  'noEnv': json['noEnv'] == null ? undefined : json['noEnv'],
118
124
  'snapshots': json['snapshots'] == null ? undefined : json['snapshots'],
125
+ 'failFast': json['failFast'] == null ? undefined : json['failFast'],
119
126
  'setupScript': json['setupScript'] == null ? undefined : json['setupScript'],
120
127
  'org': json['org'] == null ? undefined : json['org'],
121
128
  'teamId': json['teamId'] == null ? undefined : json['teamId'],
@@ -140,6 +147,7 @@ export function CreateSandboxRequestToJSONTyped(value?: CreateSandboxRequest | n
140
147
  'environment': value['environment'],
141
148
  'noEnv': value['noEnv'],
142
149
  'snapshots': value['snapshots'],
150
+ 'failFast': value['failFast'],
143
151
  'setupScript': value['setupScript'],
144
152
  'org': value['org'],
145
153
  'teamId': value['teamId'],
@@ -22,6 +22,7 @@ export * from './CommandRequest';
22
22
  export * from './CommandResponse';
23
23
  export * from './CommandStartedResponse';
24
24
  export * from './CommandStatusResponse';
25
+ export * from './CommandStreamFrame';
25
26
  export * from './CompletionEvent';
26
27
  export * from './Conversation';
27
28
  export * from './ConversationsResponse';