@shardflux/sdk 0.12.0 → 0.13.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.
@@ -80,6 +80,45 @@ export interface paths {
80
80
  * `503 service_unavailable` (`no_execution_host`: no host with
81
81
  * protocol feature `file_first` has room; retry), secret resolution
82
82
  * errors as for processful starts.
83
+ *
84
+ * Burst execution (contracts §33, not public yet): `burst: always` runs
85
+ * the command on a larger, short-lived burst VM on the workspace's
86
+ * host over a copy of the workspace disk and applies its file changes
87
+ * back when it exits. The session is read, streamed and attached like
88
+ * any other; it carries `burst` (BurstSummary) and cannot be signalled
89
+ * or canceled (`409 conflict`, `details.reason burst_not_supported`).
90
+ * Refusals: `422 validation_failed` with `details.reason`
91
+ * `burst_mode_not_supported` (`auto`), `burst_not_supported` (stdin),
92
+ * `burst_size_exceeds_plan` (`burst_vcpus`/`burst_memory_mib` above the
93
+ * plan's per-workspace ceilings; `details.field`, `details.limit`);
94
+ * `409 burst_unavailable` with `details.reason` `not_available` (no
95
+ * entitlement `policy.burst_exec`, or the host lacks protocol feature
96
+ * `burst_exec`), `layout_unsupported`, `shared_volumes`,
97
+ * `host_capacity`, `fence_not_drained`, `workspace_fenced`,
98
+ * `apply_pending`, `park_failed`, `workspace_resumed`, `interrupted`;
99
+ * `409 burst_apply_failed` (`details.reason` `disk_full` or
100
+ * `apply_failed`, `details.applied_entries`, `details.pending_entries`;
101
+ * the workspace refuses writes until a retry with the same
102
+ * `session_id` completes the apply). A refusal the host gives within
103
+ * the first seconds is the start's answer; a later one ends the
104
+ * session (`failed_to_start` for `burst_unavailable`, `lost` for
105
+ * `burst_apply_failed`), is recorded in `burst.error`, and is the
106
+ * output stream's final `error` event. A retry with the same
107
+ * `session_id` replays the recorded outcome (the host journals the
108
+ * burst by the exec's operation id) or resumes an unfinished apply.
109
+ *
110
+ * Start and follow in one request: a processful start sent with
111
+ * `Accept: application/x-ndjson` (or `text/event-stream`) answers 200
112
+ * with the session's output stream, as `GET .../output?follow=true`
113
+ * from offset 0 (output events, `exit`, a final `error`), and
114
+ * `X-Exec-Session-Id` names the session. The stream slot is taken
115
+ * before the command starts (`503 service_unavailable` when the
116
+ * gateway has no stream slot: nothing ran). Headers are sent as soon
117
+ * as the command started, before any output. A `failed_to_start`
118
+ * session, a refusal and a file-first execution keep their JSON
119
+ * answers. A replayed `session_id` streams the existing session and
120
+ * never runs it again; after a dropped stream, reconnect with
121
+ * `GET .../output` from the byte offsets already read.
83
122
  */
84
123
  post: operations["execStart"];
85
124
  delete?: never;
@@ -225,7 +264,16 @@ export interface paths {
225
264
  };
226
265
  get?: never;
227
266
  put?: never;
228
- /** SIGTERM the process group, SIGKILL after grace */
267
+ /**
268
+ * SIGTERM the process group, SIGKILL after grace
269
+ * @description Sends SIGTERM to the session's process group and SIGKILL after
270
+ * `grace_ms` (0 to 60000; 0 or omitted is 5000). Answers when the
271
+ * command has ended: at once when SIGTERM ends it, otherwise after the
272
+ * grace and the SIGKILL. A `grace_ms` outside the range is `422
273
+ * validation_failed`
274
+ * (`details.field` `grace_ms`, `details.minimum`, `details.maximum`).
275
+ * An ended session is returned as it is.
276
+ */
229
277
  post: operations["execCancel"];
230
278
  delete?: never;
231
279
  options?: never;
@@ -293,7 +341,11 @@ export interface paths {
293
341
  get: operations["ptyGet"];
294
342
  put?: never;
295
343
  post?: never;
296
- /** Close (SIGHUP, then SIGKILL after grace) */
344
+ /**
345
+ * Close (SIGHUP, then SIGKILL after grace)
346
+ * @description Sends SIGHUP to the session's process group and SIGKILL 2 s later
347
+ * if it is still running; answers once it has ended.
348
+ */
297
349
  delete: operations["ptyClose"];
298
350
  options?: never;
299
351
  head?: never;
@@ -744,8 +796,9 @@ export interface paths {
744
796
  * @description `idle_since` = max(`last_tool_at`, `last_attach_at`, `keepalive_until`,
745
797
  * `running_since`, the work horizon of running exec commands) (null when
746
798
  * none is known; in the future while a keepalive or a running command is
747
- * active). A running exec command counts as work until min(its start +
748
- * `IDLE_COMMAND_MAX_SECONDS`, its start + `timeout_ms`), and its end is
799
+ * active). A running exec command counts as work until it ends or its
800
+ * timeout passes: its start + `timeout_ms` when it has one, else its
801
+ * start + `IDLE_COMMAND_MAX_SECONDS` (1 hour by default). Its end is
749
802
  * activity (contracts §20.6): an end seen without a client call is
750
803
  * recorded in `last_attach_at`, which is work but not a tool call.
751
804
  * `suspend_at` = `idle_since` + `idle_minutes` when
@@ -823,7 +876,7 @@ export type webhooks = Record<string, never>;
823
876
  export interface components {
824
877
  schemas: {
825
878
  /** @enum {string} */
826
- ErrorCode: "bad_request" | "unauthenticated" | "forbidden" | "not_found" | "conflict" | "stale_epoch" | "workspace_not_running" | "validation_failed" | "payload_too_large" | "range_not_satisfiable" | "rate_limited" | "capacity_pending" | "dependency_unavailable" | "timeout" | "internal_error" | "service_unavailable" | "workspace_busy";
879
+ ErrorCode: "bad_request" | "unauthenticated" | "forbidden" | "not_found" | "conflict" | "stale_epoch" | "workspace_not_running" | "validation_failed" | "payload_too_large" | "range_not_satisfiable" | "rate_limited" | "capacity_pending" | "dependency_unavailable" | "timeout" | "internal_error" | "service_unavailable" | "workspace_busy" | "burst_unavailable" | "burst_apply_failed";
827
880
  ErrorBody: {
828
881
  error: {
829
882
  code: components["schemas"]["ErrorCode"];
@@ -872,7 +925,10 @@ export interface components {
872
925
  stdin?: string;
873
926
  /** Format: int64 */
874
927
  timeout_ms?: number;
875
- /** Format: int64 */
928
+ /**
929
+ * Format: int64
930
+ * @description Time between the SIGTERM and the SIGKILL when timeout_ms ends the command; 0 or omitted is 5000.
931
+ */
876
932
  kill_grace_ms?: number;
877
933
  secret_refs?: components["schemas"]["SecretRefs"];
878
934
  /** @description File-first workspaces (required there, refused otherwise) — the execution's idempotency key. */
@@ -883,6 +939,16 @@ export interface components {
883
939
  * @default 1048576
884
940
  */
885
941
  output_limit_bytes?: number;
942
+ /**
943
+ * @description Burst execution (contracts §33): `always` runs this run-to-completion command on a larger, short-lived burst VM and applies its file changes back. Needs entitlement `policy.burst_exec` and a layered processful workspace; not with stdin. `auto` is reserved (422 validation_failed, details.reason burst_mode_not_supported).
944
+ * @default never
945
+ * @enum {string}
946
+ */
947
+ burst?: "never" | "always";
948
+ /** @description The burst VM's vCPUs (burst always only; default the host's, 8), at most the plan's workspace CPU ceiling. */
949
+ burst_vcpus?: number;
950
+ /** @description The burst VM's memory in MiB (burst always only; default the host's, 8192), at most the plan's workspace memory ceiling. */
951
+ burst_memory_mib?: number;
886
952
  };
887
953
  /** @description Names of customer secrets (contracts §17) to inject as environment variables NAME=value of this process only. The cell resolves them at session start through the API with the caller's tool token (permission-checked and audited by the API); values are never logged, persisted or returned by the cell. Any name the caller may not use (unknown, not permitted for this workspace/project/tool) refuses the whole start with 403 forbidden (details.reason secret_not_available, details.names); nothing is started. A name that is also a key of `env` is refused (422 validation_failed). Requires a workspace tool token (browser stream tickets cannot resolve secrets: 403, details.reason secret_refs_require_tool_token). Resolution failures: 401 (token revoked/expired), 409 stale_epoch, 429 rate_limited, 503 dependency_unavailable. A retried start with the same session_id re-resolves the names; if a value changed since the first start the host refuses the different request (409 conflict). */
888
954
  SecretRefs: string[];
@@ -980,6 +1046,88 @@ export interface components {
980
1046
  ended_at?: string | null;
981
1047
  /** @description Why the session ended without an exit code. For failed_to_start the command never ran and this names the cause, e.g. `working directory "/home/user/app" is not a directory` or `executable "foo" not found in PATH`. */
982
1048
  error?: string;
1049
+ memory_grow?: components["schemas"]["MemoryGrow"];
1050
+ burst?: components["schemas"]["BurstSummary"];
1051
+ };
1052
+ /** @description Burst execution (contracts §33.5): present on every session started with `burst: always`. The size, method and counts are set once the burst ended (the host's result); while it runs only host, applied and the requested size are known. */
1053
+ BurstSummary: {
1054
+ /**
1055
+ * @description Where the burst VM ran; `local` = the workspace's host (`remote` is reserved).
1056
+ * @enum {string}
1057
+ */
1058
+ host: "local" | "remote";
1059
+ /** @description The burst VM's vCPUs (the requested count while it runs, absent for the host default). */
1060
+ vcpus?: number;
1061
+ /** @description The burst VM's memory in MiB (the requested size while it runs, absent for the host default). */
1062
+ memory_mib?: number;
1063
+ /**
1064
+ * @description How the burst VM got the workspace copy.
1065
+ * @enum {string}
1066
+ */
1067
+ method?: "layer" | "clone";
1068
+ /** @description The command's file changes were applied to the workspace. */
1069
+ applied: boolean;
1070
+ /** Format: int64 */
1071
+ written_files?: number;
1072
+ /** Format: int64 */
1073
+ written_dirs?: number;
1074
+ /** Format: int64 */
1075
+ removed?: number;
1076
+ /** Format: int64 */
1077
+ written_bytes?: number;
1078
+ /** @description Processes the command left behind in the burst VM (killed; they do not survive a burst). */
1079
+ leftover_killed?: number;
1080
+ /**
1081
+ * Format: int64
1082
+ * @description Wall time of the burst minus the command's own run time.
1083
+ */
1084
+ overhead_ms?: number;
1085
+ /** @description The burst VM's own paths whose changes are never carried back (the host's denylist). */
1086
+ excluded_paths?: string[];
1087
+ /** @description The host's phase timings (ms) and counters. */
1088
+ timings?: {
1089
+ [key: string]: number;
1090
+ };
1091
+ /** @description The recorded outcome of an earlier attempt with the same session_id. */
1092
+ replayed?: boolean;
1093
+ /** @description Set when the burst failed after the start answered: burst_unavailable (the workspace is unchanged) or burst_apply_failed (details.applied_entries, details.pending_entries). */
1094
+ error?: components["schemas"]["BurstError"];
1095
+ };
1096
+ BurstError: {
1097
+ code: components["schemas"]["ErrorCode"];
1098
+ message: string;
1099
+ retryable: boolean;
1100
+ details?: {
1101
+ [key: string]: unknown;
1102
+ };
1103
+ };
1104
+ /** @description Elastic memory (contracts §32.3, §32.6): the host grew the workspace's memory before this exec started (the exec waited for it). Present only on the session returned by the start that grew the VM; absent when no grow ran (fixed workspaces, or already at the exec size). */
1105
+ MemoryGrow: {
1106
+ /**
1107
+ * @description delivered: the whole grow; partial: less than wanted; missed: nothing could be plugged; failed: the plug did not converge or errored.
1108
+ * @enum {string}
1109
+ */
1110
+ outcome: "delivered" | "partial" | "missed" | "failed";
1111
+ /**
1112
+ * Format: int64
1113
+ * @description Guest memory before the grow (MiB).
1114
+ */
1115
+ from_mib: number;
1116
+ /**
1117
+ * Format: int64
1118
+ * @description Guest memory the grow aimed for (MiB).
1119
+ */
1120
+ want_mib: number;
1121
+ /**
1122
+ * Format: int64
1123
+ * @description Guest memory after the grow (MiB).
1124
+ */
1125
+ got_mib: number;
1126
+ /**
1127
+ * Format: int64
1128
+ * @description Trigger to plugged and guest MemTotal settled (ms, rounded).
1129
+ */
1130
+ deliver_ms: number;
983
1131
  };
984
1132
  OutputEvent: {
985
1133
  /** @enum {string} */
@@ -999,7 +1147,10 @@ export interface components {
999
1147
  /** @enum {string} */
1000
1148
  type: "signal" | "cancel";
1001
1149
  signal?: components["schemas"]["SignalValue"];
1002
- /** Format: int64 */
1150
+ /**
1151
+ * Format: int64
1152
+ * @description For cancel, as CancelRequest.grace_ms; out of range is an `error` event (validation_failed).
1153
+ */
1003
1154
  grace_ms?: number;
1004
1155
  };
1005
1156
  /** @description Signal number (1-64) or name (e.g. "SIGTERM", "TERM"). */
@@ -1026,7 +1177,10 @@ export interface components {
1026
1177
  only_leader?: boolean;
1027
1178
  };
1028
1179
  CancelRequest: {
1029
- /** Format: int64 */
1180
+ /**
1181
+ * Format: int64
1182
+ * @description Time between the SIGTERM and the SIGKILL; 0 or omitted is 5000.
1183
+ */
1030
1184
  grace_ms?: number;
1031
1185
  };
1032
1186
  PtyOpenRequest: {
@@ -1545,12 +1699,16 @@ export interface operations {
1545
1699
  };
1546
1700
  };
1547
1701
  responses: {
1548
- /** @description The session already existed; nothing was run again (processful), or the recorded result of an existing execution (file-first). */
1702
+ /** @description An existing session/result, or followed output when a processful start accepts NDJSON/SSE. A failed-to-start session stays JSON. */
1549
1703
  200: {
1550
1704
  headers: {
1705
+ /** @description The streamed session id; replay/reconnect use the same session and byte offsets. */
1706
+ "X-Exec-Session-Id"?: string;
1551
1707
  [name: string]: unknown;
1552
1708
  };
1553
1709
  content: {
1710
+ "application/x-ndjson": string;
1711
+ "text/event-stream": string;
1554
1712
  "application/json": components["schemas"]["ExecSession"] | components["schemas"]["ExecutionResult"];
1555
1713
  };
1556
1714
  };
package/dist/http.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { RetryRecord } from './progress.js';
2
- export declare const SDK_VERSION = "0.12.0";
2
+ export declare const SDK_VERSION = "0.13.0";
3
3
  export interface RequestOptions {
4
4
  query?: Record<string, string | number | boolean | undefined | null>;
5
5
  json?: unknown;
@@ -13,6 +13,11 @@ export interface RequestOptions {
13
13
  signal?: AbortSignal;
14
14
  /** Override the client's default request timeout (ms); 0 disables it (streams). */
15
15
  timeoutMs?: number;
16
+ /**
17
+ * Bounds each attempt until the response headers arrive (ms), leaving the body unbounded: a stream that answers a
18
+ * start (exec.run's combined start and output). Usually with `timeoutMs: 0`.
19
+ */
20
+ headersTimeoutMs?: number;
16
21
  /** Called before each retry of a transient failure (lifecycle timing records these). */
17
22
  onRetry?: (retry: Omit<RetryRecord, 'atMs'>) => void;
18
23
  }
package/dist/http.js CHANGED
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import { ShardfluxApiError, ShardfluxProtocolError, apiError, isErrorBody } from "./errors.js";
10
10
  import { describeFailure } from "./progress.js";
11
- export const SDK_VERSION = '0.12.0';
11
+ export const SDK_VERSION = '0.13.0';
12
12
  export const defaultSleep = (ms) => new Promise((r) => setTimeout(r, ms));
13
13
  /** One private HTTP/1.1 pool on Node 26+, shared by SDK clients. No global dispatcher changes. */
14
14
  let nodeFetch;
@@ -108,7 +108,13 @@ export class HttpClient {
108
108
  }
109
109
  const timeoutMs = init.timeoutMs ?? this.opts.timeoutMs;
110
110
  const timeout = timeoutMs > 0 ? AbortSignal.timeout(timeoutMs) : undefined;
111
- const signal = timeout && init.signal ? AbortSignal.any([timeout, init.signal]) : (timeout ?? init.signal);
111
+ const headersMs = init.headersTimeoutMs ?? 0;
112
+ const headersAbort = headersMs > 0 ? new AbortController() : undefined;
113
+ const headersTimer = headersAbort
114
+ ? setTimeout(() => headersAbort.abort(new DOMException('The response headers timed out.', 'TimeoutError')), headersMs)
115
+ : undefined;
116
+ const signals = [timeout, init.signal, headersAbort?.signal].filter((s) => s !== undefined);
117
+ const signal = signals.length > 1 ? AbortSignal.any(signals) : signals[0];
112
118
  let res;
113
119
  try {
114
120
  res = await this.opts.fetch(url, { method, headers, ...(body === undefined ? {} : { body: body }), ...(signal ? { signal } : {}) });
@@ -119,10 +125,13 @@ export class HttpClient {
119
125
  if (!retriable || attempt >= this.opts.maxRetries)
120
126
  throw err;
121
127
  const delayMs = Math.min(2_000, 200 * 2 ** attempt);
122
- init.onRetry?.({ request: `${method} ${path}`, attempt: attempt + 1, cause: describeFailure(err, timeoutMs), delayMs });
128
+ init.onRetry?.({ request: `${method} ${path}`, attempt: attempt + 1, cause: describeFailure(err, headersAbort?.signal.aborted ? headersMs : timeoutMs), delayMs });
123
129
  await sleep(delayMs);
124
130
  continue;
125
131
  }
132
+ finally {
133
+ clearTimeout(headersTimer);
134
+ }
126
135
  if (res.ok) {
127
136
  if (this.opts.onSuccess) {
128
137
  try {
package/dist/index.d.ts CHANGED
@@ -15,8 +15,8 @@
15
15
  export type { components, operations, paths } from './generated/app-api.js';
16
16
  export type { components as CellComponents, paths as CellPaths } from './generated/cell-api.js';
17
17
  export { BillingApi, Shardflux, WorkspacesApi, fetchBillingCatalog, pickByKey } from './client.js';
18
- export type { AgentSession, BillingCatalog, BillingSubscription, Caps, CheckoutSession, DiskLayout, Entitlements, FindByKeyOptions, ForkTarget, Invoice, InvoicePage, LifetimeFilter, ListParams, Me, OpenParams, OpenResponse, Operation, Page, PortalSession, PurposeFilter, ResetWorkspaceBody, ResumeAnswer, ResumeRequestOptions, ResumeResponse, ShardfluxOptions, SuspendRequest, SuspendWhenIdleOptions, SuspendWhenIdleResponse, SuspendWhenIdleResult, UpdatePolicy, WaitOptions, WorkspaceInputs, WorkspaceLifetime, WorkspaceOrigin, WorkspacePurpose, WorkspaceView, } from './client.js';
19
- export type { FinishedOperation, LifecycleOptions, ResumeOptions, SuspendOptions, WaitedLifecycleOptions, WaitedResumeOptions, WaitedSuspendOptions } from './lifecycle.js';
18
+ export type { AgentSession, AllocationMode, BillingCatalog, BillingSubscription, Caps, CheckoutSession, DiskLayout, Entitlements, FindByKeyOptions, ForkTarget, Invoice, InvoicePage, LifetimeFilter, ListParams, Me, OpenParams, OpenResponse, Operation, Page, PortalSession, PurposeFilter, ResetWorkspaceBody, ResumeAnswer, ResumeRequestOptions, ResumeResponse, ShardfluxOptions, SuspendRequest, SuspendWhenIdleOptions, SuspendWhenIdleResponse, SuspendWhenIdleResult, WaitOptions, WorkspaceInputs, WorkspaceLifetime, WorkspaceMemory, WorkspaceOrigin, WorkspacePurpose, WorkspaceView, } from './client.js';
19
+ export type { FinishedOperation, ForkOptions, LifecycleOptions, ResumeOptions, SuspendOptions, WaitedForkOptions, WaitedLifecycleOptions, WaitedResumeOptions, WaitedSuspendOptions } from './lifecycle.js';
20
20
  export { durabilityOf, formatTiming, isDurable, lostSuspendOf } from './progress.js';
21
21
  export type { Durability, LostSuspend, LifecycleAction, LifecyclePhase, LifecycleTiming, ProgressEvent, ProgressListener, RetryRecord, ServerTiming, TimingOutcome, TimingPhase, } from './progress.js';
22
22
  export { FEEDBACK_CATEGORIES, FEEDBACK_MESSAGE_MAX_LENGTH } from './feedback.js';
@@ -28,7 +28,7 @@ export { TemplateFileError, packDirectory, parseTemplateText, readTemplateFile }
28
28
  export type { PackedFile, YamlParser } from './template-file.js';
29
29
  export { tarEnd, tarHeader, tarPadding } from './tar.js';
30
30
  export type { TarEntry, TarEntryType } from './tar.js';
31
- export type { BuildFromFileEvent, BuildFromFileOptions, BuildFromFileResult, BuildFromRecipeOptions, BuilderAvailability, CreateDraftBody, CreateDraftParams, CreateTemplateBuildParams, CreateTestInstanceBody, CreateVersionTestInstanceBody, CreateVersionTestInstanceParams, DraftOpened, LocalUpload, DraftState, OpenTestInstanceParams, OrgTemplateStorage, PublishDraftBody, PublishDraftParams, PutUploadOptions, SaveAsTemplateBody, SaveAsTemplateParams, SaveAsTemplateResponse, TemplateBuild, TemplateBuildLogUrl, TemplateBuildRecipeV2, TemplateBuildRegistrationState, TemplateBuildState, TemplateCategory, TemplateDefaults, TemplateDefaultsInput, TemplateDetail, TemplateDiffChange, TemplateDiffEntry, TemplateDiffPage, TemplateDiffParams, TemplateDraft, TemplateDraftSummary, TemplateEgressDefault, TemplateFileEntry, TemplateFilePage, TemplateFilesParams, TemplateFilesSummary, TemplateInput, TemplateLanguage, TemplateLanguages, TemplateOwner, TemplatePackage, TemplatePackageEcosystem, TemplatePackagePage, TemplateRecipe, TemplateRecipeV2, TemplateRecipeV2File, TemplateService, TemplateSettings, TemplateSettingsInput, TemplateSource, TemplateStartCommand, TemplateStorage, TemplateStorageWarning, TemplateSummary, TemplateUpload, TemplateUploadRequest, TemplateUploadResponse, TemplateUploadResult, TemplateVersion, TemplateVersionRecipe, TemplateVersionState, UploadData, WaitForBuildOptions, WorkspaceStartup, } from './templates.js';
31
+ export type { BuildFromFileEvent, BuildFromFileOptions, BuildFromFileResult, BuildFromRecipeOptions, BuilderAvailability, CreateDraftBody, CreateDraftParams, CreateTemplateBuildParams, CreateTestInstanceBody, CreateVersionTestInstanceBody, CreateVersionTestInstanceParams, DraftOpened, LocalUpload, DraftState, OpenTestInstanceParams, OrgTemplateStorage, PublishDraftBody, PublishDraftParams, PutUploadOptions, SaveAsTemplateBody, SaveAsTemplateParams, SaveAsTemplateResponse, TemplateBuild, TemplateBuildLogUrl, TemplateBuildRecipeV2, TemplateBuildRegistrationState, TemplateBuildState, TemplateCategory, TemplateDefaults, TemplateDefaultsInput, TemplateDetail, TemplateDiffChange, TemplateDiffEntry, TemplateDiffPage, TemplateDiffParams, TemplateDraft, TemplateDraftSummary, TemplateEgressDefault, TemplateFileEntry, TemplateFilePage, TemplateFilesParams, TemplateFilesSummary, TemplateInput, TemplateLanguage, TemplateLanguages, TemplateOwner, TemplatePackage, TemplatePackageEcosystem, TemplatePackagePage, TemplateRecipe, TemplateRecipeV2, TemplateRecipeV2File, TemplateService, TemplateSettings, TemplateSettingsInput, TemplateSource, TemplateStartCommand, TemplateStorage, TemplateStorageWarning, TemplateSummary, TemplateUpload, TemplateUploadRequest, TemplateUploadResponse, TemplateUploadResult, TemplateVersion, TemplateVersionImmutable, TemplateVersionRecipe, TemplateVersionState, UploadData, WaitForBuildOptions, WorkspaceStartup, } from './templates.js';
32
32
  export { SecretsApi, WorkspaceSecrets } from './secrets.js';
33
33
  export type { BoundSecretStatus, CreateOrganizationSecretParams, CreateSecretParams, Secret, SecretAccessEvent, SecretPermissions, SecretScope, SecretVersion, UpdateSecretParams, WorkspaceSecretBindings, } from './secrets.js';
34
34
  export { EgressPolicyApi } from './egress.js';
@@ -42,7 +42,7 @@ export type { HintOptions, HintResult, WakeOptions } from './workspace.js';
42
42
  export { CellClient, DEFAULT_TRANSITION_TIMEOUT_MS, cellPath, ndjson } from './cell.js';
43
43
  export { EXECUTION_ID, ExecutionResult, newExecutionId } from './executions.js';
44
44
  export type { ExecutionChange, ExecutionError, ExecutionGetOptions, ExecutionResultBody, ExecutionRunOptions, ExecutionState } from './executions.js';
45
- export type { TreeRevisionOptions, BrowserContent, BrowserContentRequest, BrowserScreenshotRequest, CellClientOptions, ExecSession, ExecStartRequest, FileEdit, FileInfo, FileList, FilePatchEdit, FilePatchParams, FilePatchRequest, FilePatchResult, FileReadResult, FileRevision, FileSearchMatch, FileSearchOptions, FileSearchRequest, FileSearchResponse, FileSearchResult, FileWriteResult, GitResult, GitStatus, OutputEvent, ProcessList, PtyOpenRequest, PtySession, Residency, RunOptions, RunResult, ServedFrom, Signal, WakeHintResult, WorkspaceChange, WorkspaceChangeKind, WorkspaceChangesPage, WorkspaceChangesParams, WorkspaceChangesSummary, } from './cell.js';
45
+ export type { TreeRevisionOptions, BrowserContent, BrowserContentRequest, BrowserScreenshotRequest, CellClientOptions, ExecSession, ExecStartRequest, MemoryGrow, BurstSummary, BurstError, FileEdit, FileInfo, FileList, FilePatchEdit, FilePatchParams, FilePatchRequest, FilePatchResult, FileReadResult, FileRevision, FileSearchMatch, FileSearchOptions, FileSearchRequest, FileSearchResponse, FileSearchResult, FileWriteResult, GitResult, GitStatus, OutputEvent, ProcessList, PtyOpenRequest, PtySession, Residency, RunOptions, RunResult, ServedFrom, Signal, WakeHintResult, WorkspaceChange, WorkspaceChangeKind, WorkspaceChangesPage, WorkspaceChangesParams, WorkspaceChangesSummary, } from './cell.js';
46
46
  export { ToolTokenManager } from './tokens.js';
47
47
  export type { ToolName, ToolToken, ToolTokenOptions } from './tokens.js';
48
48
  export { ToolArgumentError, executeToolCall, toAnthropicTools, toOpenAITools, validateArgs, workspaceTools } from './tools.js';
@@ -61,6 +61,11 @@ export interface ResumeOptions extends LifecycleOptions {
61
61
  export type WaitedResumeOptions = ResumeOptions & {
62
62
  wait: true | WaitOptions;
63
63
  };
64
+ /** A waited fork (0.13.0+) returns the target view and token together when the API supports it. */
65
+ export type ForkOptions = ResumeOptions;
66
+ export type WaitedForkOptions = ForkOptions & {
67
+ wait: true | WaitOptions;
68
+ };
64
69
  /** Internal: the trace a wait continues instead of starting its own (open(), wake() and waited lifecycle calls). */
65
70
  export declare const TRACE: unique symbol;
66
71
  /** Internal: work a workspace handle does after the operation finished, inside the same trace (refreshing its view). */
@@ -88,6 +93,7 @@ export declare function waitOptionsOf(opts: LifecycleOptions): WaitOptions | nul
88
93
  * Starts a lifecycle operation with `start` and, when `opts.wait` asks for it, waits for it to finish. The trace covers
89
94
  * the request, every observed state, and `AFTER_WAIT`; it ends with `done` either way.
90
95
  */
91
- export declare function runLifecycle(ctx: ClientContext, kind: LifecycleAction, workspaceId: string, start: (init: Pick<RequestOptions, 'onRetry'>) => Promise<Operation>, opts: InternalLifecycleOptions, capture?: {
96
+ export declare function runLifecycle(ctx: ClientContext, kind: LifecycleAction, workspaceId: string, start: (init: Pick<RequestOptions, 'onRetry'>, trace: Trace) => Promise<Operation>, opts: InternalLifecycleOptions, capture?: {
92
97
  settle?: boolean;
98
+ requestReason?: string | null;
93
99
  }): Promise<Operation>;
package/dist/lifecycle.js CHANGED
@@ -28,8 +28,8 @@ export async function runLifecycle(ctx, kind, workspaceId, start, opts, capture
28
28
  const pending = capture.settle ? ctx.captures.settle(workspaceId) : undefined;
29
29
  if (pending)
30
30
  await trace.span('capture_flush', () => pending);
31
- trace.phase('request');
32
- const operation = await start({ onRetry: trace.onRetry });
31
+ trace.phase('request', capture.requestReason ?? null);
32
+ const operation = await start({ onRetry: trace.onRetry }, trace);
33
33
  trace.observe(operation);
34
34
  if (!waitOpts)
35
35
  return operation;
@@ -176,6 +176,17 @@ export interface TemplateVersion {
176
176
  introduced_in_version: number | null;
177
177
  }>;
178
178
  storage: TemplateStorage;
179
+ /**
180
+ * Immutable paths (0.13.0): the directories this version declares read-only and the size of its image, or null when
181
+ * it declares none. Workspaces of the template mount these paths from the template's newest published version (the
182
+ * open version) and pick up a newer one when they cold-boot or resume.
183
+ */
184
+ immutable: TemplateVersionImmutable | null;
185
+ }
186
+ /** A version's immutable paths (0.13.0): the read-only directories (byte order) and the bytes of their image. */
187
+ export interface TemplateVersionImmutable {
188
+ paths: string[];
189
+ bytes: number;
179
190
  }
180
191
  /** Summary of an organization template's live draft on the template view (null when none). */
181
192
  export interface TemplateDraftSummary {
@@ -207,8 +218,6 @@ export interface TemplateSummary {
207
218
  open_version: TemplateVersion | null;
208
219
  /** The live draft (organization templates in dev mode), or null. */
209
220
  draft: TemplateDraftSummary | null;
210
- /** Reserved (T2): always `pinned` in T1. */
211
- update_policy: 'pinned' | 'auto';
212
221
  /** Platform templates: `os` or `stack` (0.7.0); organization templates: null. */
213
222
  category: TemplateCategory | null;
214
223
  }
@@ -333,9 +342,14 @@ export interface TemplateBuild {
333
342
  archived_at: string | null;
334
343
  } | null;
335
344
  };
345
+ /**
346
+ * Why the build failed. `details` carries code-specific fields (0.13.0): `immutable_path_missing` (an immutable path is
347
+ * not a directory in the built filesystem) names it in `details.path`; `immutable_image_too_large` has none.
348
+ */
336
349
  failure: {
337
350
  code: string;
338
351
  message: string;
352
+ details?: Record<string, unknown>;
339
353
  } | null;
340
354
  log: {
341
355
  state: 'none' | 'available' | 'expired';
@@ -361,6 +375,12 @@ export interface TemplateBuild {
361
375
  squashed: boolean | null;
362
376
  /** Organization bytes of the produced chain (limit: the plan's template_org_bytes_max). */
363
377
  org_bytes: number | null;
378
+ /**
379
+ * The immutable paths the produced version declares (0.13.0), in byte order: the recipe's `immutable`, else the list
380
+ * of the template's open version (a save from a workspace: the target template's open version's, else the
381
+ * workspace's version's). Empty for none.
382
+ */
383
+ immutable_paths: string[];
364
384
  }
365
385
  export interface TemplateRecipe {
366
386
  /** `<template slug>@<version>`, referenced in the Dockerfile as `FROM shardflux-base`. */
@@ -386,7 +406,9 @@ export interface CreateTemplateBuildParams {
386
406
  /**
387
407
  * Recipe v1 (a Dockerfile) or recipe v2 (0.7.0; `schema: "shardflux.template-recipe.v2"`: languages, packages,
388
408
  * uploaded files, steps, auto network and settings). Recipe v2 files reference uploads
389
- * (`templates.uploads.put()`); `buildFromFile()` / `buildFromRecipe()` upload local `from` paths for you.
409
+ * (`templates.uploads.put()`); `buildFromFile()` / `buildFromRecipe()` upload local `from` paths for you. A recipe v2
410
+ * may declare `immutable` (0.13.0): up to 8 directories every workspace of the template mounts read-only from its
411
+ * newest published version (omitted: the open version's list; a new version keeps every path of it).
390
412
  */
391
413
  recipe: TemplateRecipe | TemplateRecipeV2;
392
414
  /** Publish the produced version as soon as it is registered (default true); false leaves it for the owner/admin publish route. */
package/dist/tools.d.ts CHANGED
@@ -85,6 +85,13 @@ export interface WorkspaceToolsOptions {
85
85
  * with `workspace.executions.get(id)`.
86
86
  */
87
87
  onExecution?: (executionId: string) => void;
88
+ /**
89
+ * Offer burst execution on the processful `exec` tool (0.13.0; off by default: it needs the
90
+ * organization's burst execution entitlement). The tool then takes `burst`
91
+ * (`'always'` runs the command on a larger, short-lived burst VM and applies its file changes back), `burst_vcpus`
92
+ * and `burst_memory_mib`, and its result adds `burst` (the summary) for a burst. The file-first `exec` is unchanged.
93
+ */
94
+ burst?: boolean;
88
95
  }
89
96
  /** Builds the tool list for a workspace. Synchronous: tokens are fetched on first use. */
90
97
  export declare function workspaceTools(workspace: Workspace, opts?: WorkspaceToolsOptions): WorkspaceTool[];