@shardflux/sdk 0.10.2 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cell.d.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  * (token expired or revoked early) invalidates the token and retries once with
8
8
  * a fresh one; the retried request is safe because the gateway rejected the
9
9
  * first before any effect (and exec/PTY starts are idempotent by session_id).
10
- * The same holds for lifecycle refusals (contracts §20.4): `workspace_busy` is
10
+ * The same holds for lifecycle refusals: `workspace_busy` is
11
11
  * waited out and `workspace_not_running` wakes the workspace, then the call is
12
12
  * retried, all within one bounded transition budget per call.
13
13
  *
@@ -15,7 +15,7 @@
15
15
  * `exec.run()` survives gateway restarts/disconnects by reconnecting with the
16
16
  * offsets it already processed; it never starts the command a second time.
17
17
  *
18
- * File-first workspaces (contracts §29) serve the files routes from a
18
+ * File-first workspaces serve the files routes from a
19
19
  * versioned tree and run commands as executions (`executions.run()`); the
20
20
  * client tracks the tree revision every response reports (`X-Tree-Revision`)
21
21
  * and, when it knows the workspace's mode, refuses calls the mode does not
@@ -39,20 +39,20 @@ export type ProcessList = S['ProcessList'];
39
39
  export type FileInfo = S['FileInfo'];
40
40
  export type FileList = S['FileList'];
41
41
  export type FileWriteResult = S['FileWriteResult'];
42
- /** Search request/result of `POST /files/search` (contracts §26.1). */
42
+ /** Search request/result of `POST /files/search`. */
43
43
  export type FileSearchRequest = S['FileSearchRequest'];
44
44
  export type FileSearchMatch = S['FileSearchMatch'];
45
45
  export type FileSearchResult = S['FileSearchResult'];
46
- /** One text edit of `POST /files/patch` (contracts §26.2), as sent on the wire. */
46
+ /** One text edit of `POST /files/patch`, as sent on the wire. */
47
47
  export type FileEdit = S['FileEdit'];
48
48
  export type FilePatchRequest = S['FilePatchRequest'];
49
49
  export type FilePatchResult = S['FilePatchResult'];
50
50
  /** A content SHA-256 (lowercase hex), or `absent` for a path that must not exist. */
51
51
  export type FileRevision = S['FileRevision'];
52
52
  export type WakeHintResult = S['WakeHintResult'];
53
- /** Where a running workspace's VM is (contracts §25.1): resident, frozen, hibernated or restoring. */
53
+ /** Where a running workspace's VM is: resident, frozen, hibernated or restoring. */
54
54
  export type Residency = WakeHintResult['residency'];
55
- /** `X-Served-From`: `disk` when a read was served from a suspended or hibernated workspace's disk (contracts §26.4). */
55
+ /** `X-Served-From`: `disk` when a read was served from a suspended or hibernated workspace's disk. */
56
56
  export type ServedFrom = 'guest' | 'disk';
57
57
  /** `files.readWithInfo()`: the bytes plus what the gateway reported about the file. */
58
58
  export interface FileReadResult {
@@ -122,7 +122,7 @@ export type BrowserScreenshotRequest = S['BrowserScreenshotRequest'];
122
122
  export type BrowserContentRequest = S['BrowserContentRequest'];
123
123
  export type BrowserContent = S['BrowserContent'];
124
124
  export type Signal = S['SignalValue'];
125
- /** One entry of a workspace's changes against its template (contracts §19.10). */
125
+ /** One entry of a workspace's changes against its template. */
126
126
  export type WorkspaceChange = S['WorkspaceChange'];
127
127
  export type WorkspaceChangeKind = WorkspaceChange['change'];
128
128
  export type WorkspaceChangesSummary = S['WorkspaceChangesSummary'];
@@ -155,8 +155,8 @@ export interface CellClientOptions {
155
155
  * resolves `false` when there was nothing to wake (the API already reports it running), and the refusal then
156
156
  * surfaces. It throws when the wake fails (OperationFailedError) or outlasts `timeoutMs` (OperationTimeoutError).
157
157
  * Workspace.cell() supplies `workspace.wake()`. A call refused with `workspace_not_running` wakes the workspace and is
158
- * retried; a refused call was never executed (contracts §20.4), so the retry cannot duplicate it. `null` surfaces
159
- * the refusal instead. A wake that put a new token into this client's manager (the held resume, contracts §22.6;
158
+ * retried; a refused call was never executed, so the retry cannot duplicate it. `null` surfaces
159
+ * the refusal instead. A wake that put a new token into this client's manager (the held resume;
160
160
  * `workspace.wake({ agentLabel, tools })`) is retried with it; otherwise the token is replaced before the retry.
161
161
  */
162
162
  wake?: ((timeoutMs: number, signal?: AbortSignal) => Promise<boolean | void>) | null;
@@ -174,7 +174,7 @@ export interface CellClientOptions {
174
174
  /** Internal: see CAPTURE_BARRIER. */
175
175
  [CAPTURE_BARRIER]?: (() => Promise<unknown> | undefined) | undefined;
176
176
  /**
177
- * The workspace's mode (contracts §29), or a function returning it (undefined: unknown). When known, calls the mode
177
+ * The workspace's mode, or a function returning it (undefined: unknown). When known, calls the mode
178
178
  * does not have fail at once with NotSupportedForModeError (`local` true) instead of a request: exec sessions, PTY,
179
179
  * processes, version control, browser and changes on a file-first workspace; executions and `ifTreeRevision` on a
180
180
  * processful one. Workspace.cell() supplies the workspace's.
@@ -183,7 +183,7 @@ export interface CellClientOptions {
183
183
  /** Called with every tree revision a response reports (`X-Tree-Revision`, execution results, mismatch refusals). */
184
184
  onTreeRevision?: (revision: number) => void;
185
185
  }
186
- /** `ifTreeRevision` (file-first workspaces, contracts §29.8): the tree revision a mutating files call applies to. */
186
+ /** `ifTreeRevision` (file-first workspaces): the tree revision a mutating files call applies to. */
187
187
  export interface TreeRevisionOptions {
188
188
  /**
189
189
  * Sent as `If-Match`: the call applies only while the tree is at this revision (`workspace.treeRevision`, or a
@@ -197,7 +197,7 @@ export interface TreeRevisionOptions {
197
197
  interface TransitionOptions {
198
198
  /** Wake a suspended workspace for this call (default true; exec output follow reconnects pass false). */
199
199
  wake?: boolean;
200
- /** Wait out `workspace_busy` (default true; the wake hint passes false: it is best effort). */
200
+ /** Wait out `workspace_busy` (default true; the wake hint passes false: it never waits). */
201
201
  busy?: boolean;
202
202
  }
203
203
  export declare const DEFAULT_TRANSITION_TIMEOUT_MS = 120000;
@@ -245,7 +245,7 @@ export interface RunOptions {
245
245
  /** Output reconnect attempts after a dropped stream (default 10). */
246
246
  maxReconnects?: number;
247
247
  /**
248
- * Names of customer secrets (contracts §17) the cell injects as environment variables `NAME=value` of this
248
+ * Names of customer secrets the cell injects as environment variables `NAME=value` of this
249
249
  * process only (sent as `secret_refs`). Values are resolved at session start with this workspace's tool token and
250
250
  * never returned. A name the caller may not use refuses the whole start with 403 `forbidden`
251
251
  * (details.reason `secret_not_available`, details.names) and nothing runs; a name also present in `env` is 422.
@@ -274,7 +274,7 @@ export declare class CellClient {
274
274
  */
275
275
  close(): void;
276
276
  /**
277
- * One authorized request. Refreshes the token once on stale_epoch / 401. Lifecycle transitions (contracts §20.4),
277
+ * One authorized request. Refreshes the token once on stale_epoch / 401. Lifecycle transitions,
278
278
  * bounded in total by `transitionTimeoutMs`: a call refused with `workspace_busy` is retried after `Retry-After`; one
279
279
  * refused with `workspace_not_running` (or whose token cannot be minted because the workspace is not running) wakes
280
280
  * the workspace through `wake`, given the time left, and is retried with a fresh token, at most 3 wakes per call.
@@ -314,9 +314,9 @@ export declare class CellClient {
314
314
  * the next revision (`treeRevision`, `changed`); processes, memory and files elsewhere do not survive it.
315
315
  *
316
316
  * The execution id (`executionId`, default a fresh `ex-<uuid>`) is the idempotency key: network failures and
317
- * retryable 429/5xx answers (503 `no_execution_host`: no host has room, with Retry-After) are retried with the same
318
- * id and request, at most `maxRetries` times, and an attempt that waits longer than `attemptTimeoutMs` re-attaches
319
- * with the same id. The cell answers 201 for the call that ran the command and 200 (`replayed`) with the recorded
317
+ * retryable 429/5xx answers (503 `no_execution_host`: the execution cannot be placed right now, with Retry-After) are
318
+ * retried with the same id and request, at most `maxRetries` times, and an attempt that waits longer than
319
+ * `attemptTimeoutMs` re-attaches with the same id. The cell answers 201 for the call that ran the command and 200 (`replayed`) with the recorded
320
320
  * result otherwise, so the command runs at most once. `workspace_busy` (`execution_in_progress`: another execution
321
321
  * holds the workspace) is waited out within `transitionTimeoutMs`; `execution_id_reused` (the id with another
322
322
  * request) and validation errors are thrown at once. The SDK never retries with a new id: a result whose `state` is
@@ -376,7 +376,7 @@ export declare class CellClient {
376
376
  /**
377
377
  * Like `read()`, plus the file's size, `revision` (SHA-256 of the whole file, `X-File-Revision`, for regular files of
378
378
  * 16 MiB or less; pass it as `expectedRevision` to `patch()`) and `servedFrom` (`disk` when a sleeping workspace was
379
- * read from its disk without waking it, contracts §26.4). 0.9.0+.
379
+ * read from its disk without waking it). 0.9.0+.
380
380
  */
381
381
  readWithInfo: (path: string, opts?: {
382
382
  offset?: number;
@@ -414,7 +414,7 @@ export declare class CellClient {
414
414
  overwrite?: boolean;
415
415
  } & TreeRevisionOptions) => Promise<FileInfo>;
416
416
  /**
417
- * Searches file contents under `path`, a directory or one file (contracts §26.1; 0.9.0+): matching lines in path
417
+ * Searches file contents under `path`, a directory or one file (0.9.0+): matching lines in path
418
418
  * order, bounded by `maxMatches`, a 10 s budget and 4 MiB of results (`truncated`, `stop_reason` `max_matches`,
419
419
  * `budget` or `max_bytes`). Binary files, symbolic links, special files and files above `maxFileBytes` are
420
420
  * skipped. Read-only, so transient failures (e.g. 503 `host_capacity`) are retried; a suspended workspace whose
@@ -423,7 +423,7 @@ export declare class CellClient {
423
423
  search: (path: string, pattern: string, opts?: FileSearchOptions) => Promise<FileSearchResponse>;
424
424
  /**
425
425
  * Applies text `edits` (each `oldText` must occur exactly once unless `replaceAll`; in order) or replaces the whole
426
- * file with `content`, atomically and durably (contracts §26.2; 0.9.0+). With `expectedRevision` the file must
426
+ * file with `content`, atomically and durably (0.9.0+). With `expectedRevision` the file must
427
427
  * still have that revision (`absent`: must not exist), else 409 `conflict` `revision_mismatch` with
428
428
  * `details.current_revision`. Edits that do not apply: 422 `validation_failed` `edit_not_found` / `edit_ambiguous`
429
429
  * (`details.index`), `edit_not_text`. Limits: a request of up to 7 MiB (else 413 `payload_too_large`; larger
@@ -437,7 +437,7 @@ export declare class CellClient {
437
437
  } & TreeRevisionOptions) => Promise<FilePatchResult>;
438
438
  };
439
439
  /**
440
- * `POST /wake-hint` (contracts §26.6; 0.9.0+): announces an imminent tool call so a hibernated workspace is restored
440
+ * `POST /wake-hint` (0.9.0+): announces an imminent tool call so a hibernated workspace is restored
441
441
  * ahead of it. It never wakes a suspended workspace, never waits out `workspace_busy` and is not retried: a suspended
442
442
  * workspace answers 409 `workspace_not_running` (`Workspace.hint()` then wakes it in the background).
443
443
  */
package/dist/cell.js CHANGED
@@ -200,7 +200,7 @@ export class CellClient {
200
200
  this.#closer.abort(new DOMException('The workspace handle was closed.', 'AbortError'));
201
201
  }
202
202
  /**
203
- * One authorized request. Refreshes the token once on stale_epoch / 401. Lifecycle transitions (contracts §20.4),
203
+ * One authorized request. Refreshes the token once on stale_epoch / 401. Lifecycle transitions,
204
204
  * bounded in total by `transitionTimeoutMs`: a call refused with `workspace_busy` is retried after `Retry-After`; one
205
205
  * refused with `workspace_not_running` (or whose token cannot be minted because the workspace is not running) wakes
206
206
  * the workspace through `wake`, given the time left, and is retried with a fresh token, at most 3 wakes per call.
@@ -262,7 +262,7 @@ export class CellClient {
262
262
  const before = this.tokens.current;
263
263
  if ((await this.#wake(left, signal)) === false)
264
264
  throw err; // running per the API: nothing to wait for
265
- // A held resume (contracts §22.6) handed this client a token of the woken workspace: use it. Otherwise the
265
+ // A held resume handed this client a token of the woken workspace: use it. Otherwise the
266
266
  // old token is of the previous epoch: fetch a new one.
267
267
  if (this.tokens.current === before)
268
268
  this.tokens.invalidate();
@@ -475,7 +475,7 @@ export class CellClient {
475
475
  reconnects,
476
476
  };
477
477
  }
478
- // ---- executions (file-first workspaces, contracts §29.8) -----------------------------
478
+ // ---- executions (file-first workspaces) -----------------------------
479
479
  executions = {
480
480
  /**
481
481
  * Runs argv (no shell; `['bash', '-lc', line]` for shell syntax) as an execution of this file-first workspace: a
@@ -483,9 +483,9 @@ export class CellClient {
483
483
  * the next revision (`treeRevision`, `changed`); processes, memory and files elsewhere do not survive it.
484
484
  *
485
485
  * The execution id (`executionId`, default a fresh `ex-<uuid>`) is the idempotency key: network failures and
486
- * retryable 429/5xx answers (503 `no_execution_host`: no host has room, with Retry-After) are retried with the same
487
- * id and request, at most `maxRetries` times, and an attempt that waits longer than `attemptTimeoutMs` re-attaches
488
- * with the same id. The cell answers 201 for the call that ran the command and 200 (`replayed`) with the recorded
486
+ * retryable 429/5xx answers (503 `no_execution_host`: the execution cannot be placed right now, with Retry-After) are
487
+ * retried with the same id and request, at most `maxRetries` times, and an attempt that waits longer than
488
+ * `attemptTimeoutMs` re-attaches with the same id. The cell answers 201 for the call that ran the command and 200 (`replayed`) with the recorded
489
489
  * result otherwise, so the command runs at most once. `workspace_busy` (`execution_in_progress`: another execution
490
490
  * holds the workspace) is waited out within `transitionTimeoutMs`; `execution_id_reused` (the id with another
491
491
  * request) and validation errors are thrown at once. The SDK never retries with a new id: a result whose `state` is
@@ -744,7 +744,7 @@ export class CellClient {
744
744
  /**
745
745
  * Like `read()`, plus the file's size, `revision` (SHA-256 of the whole file, `X-File-Revision`, for regular files of
746
746
  * 16 MiB or less; pass it as `expectedRevision` to `patch()`) and `servedFrom` (`disk` when a sleeping workspace was
747
- * read from its disk without waking it, contracts §26.4). 0.9.0+.
747
+ * read from its disk without waking it). 0.9.0+.
748
748
  */
749
749
  readWithInfo: async (path, opts = {}) => {
750
750
  const url = this.#p('/v1/workspaces/{workspace_id}/files');
@@ -805,7 +805,7 @@ export class CellClient {
805
805
  headers: this.#ifMatch('files.move', opts),
806
806
  }),
807
807
  /**
808
- * Searches file contents under `path`, a directory or one file (contracts §26.1; 0.9.0+): matching lines in path
808
+ * Searches file contents under `path`, a directory or one file (0.9.0+): matching lines in path
809
809
  * order, bounded by `maxMatches`, a 10 s budget and 4 MiB of results (`truncated`, `stop_reason` `max_matches`,
810
810
  * `budget` or `max_bytes`). Binary files, symbolic links, special files and files above `maxFileBytes` are
811
811
  * skipped. Read-only, so transient failures (e.g. 503 `host_capacity`) are retried; a suspended workspace whose
@@ -833,7 +833,7 @@ export class CellClient {
833
833
  },
834
834
  /**
835
835
  * Applies text `edits` (each `oldText` must occur exactly once unless `replaceAll`; in order) or replaces the whole
836
- * file with `content`, atomically and durably (contracts §26.2; 0.9.0+). With `expectedRevision` the file must
836
+ * file with `content`, atomically and durably (0.9.0+). With `expectedRevision` the file must
837
837
  * still have that revision (`absent`: must not exist), else 409 `conflict` `revision_mismatch` with
838
838
  * `details.current_revision`. Edits that do not apply: 422 `validation_failed` `edit_not_found` / `edit_ambiguous`
839
839
  * (`details.index`), `edit_not_text`. Limits: a request of up to 7 MiB (else 413 `payload_too_large`; larger
@@ -865,17 +865,17 @@ export class CellClient {
865
865
  },
866
866
  };
867
867
  /**
868
- * `POST /wake-hint` (contracts §26.6; 0.9.0+): announces an imminent tool call so a hibernated workspace is restored
868
+ * `POST /wake-hint` (0.9.0+): announces an imminent tool call so a hibernated workspace is restored
869
869
  * ahead of it. It never wakes a suspended workspace, never waits out `workspace_busy` and is not retried: a suspended
870
870
  * workspace answers 409 `workspace_not_running` (`Workspace.hint()` then wakes it in the background).
871
871
  */
872
872
  wakeHint(signal) {
873
- // Nothing of a file-first workspace sleeps: the cell would answer `resident` (contracts §29.8).
873
+ // Nothing of a file-first workspace sleeps: the cell would answer `resident`.
874
874
  if (this.mode === 'file_first')
875
875
  return Promise.resolve({ residency: 'resident' });
876
876
  return this.#json('POST', this.#p('/v1/workspaces/{workspace_id}/wake-hint'), { wake: false, busy: false, timeoutMs: 10_000, ...(signal ? { signal } : {}) });
877
877
  }
878
- // ---- changes against the template (layered workspaces, contracts §19.10) ------------------
878
+ // ---- changes against the template (layered workspaces) ------------------
879
879
  /**
880
880
  * One page of the workspace's changes against its template (needs the `files` tool). File-first workspaces: each
881
881
  * execution's result lists what it changed (`changed`); this route is refused (NotSupportedForModeError).
package/dist/client.d.ts CHANGED
@@ -28,9 +28,9 @@ import { CaptureRegistry } from './capture.js';
28
28
  import type { FeedbackReceipt, SendFeedbackParams } from './feedback.js';
29
29
  export type WorkspaceView = components['schemas']['Workspace'];
30
30
  export type Operation = components['schemas']['Operation'];
31
- /** persistent (kept until deleted) or session (discarded when the session ends: close(), idle timeout; contracts §19.11). */
31
+ /** persistent (kept until deleted) or session (discarded when the session ends: close(), idle timeout). */
32
32
  export type WorkspaceLifetime = components['schemas']['WorkspaceLifetime'];
33
- /** legacy (one disk) or layered (the template chain read-only plus a workspace layer; contracts §19.2). */
33
+ /** legacy (one disk) or layered (the template chain read-only plus a workspace layer). */
34
34
  export type DiskLayout = components['schemas']['DiskLayout'];
35
35
  /** standard, template_draft (a template's dev-mode draft) or template_test (a test instance of a draft state). */
36
36
  export type WorkspacePurpose = components['schemas']['WorkspacePurpose'];
@@ -56,7 +56,7 @@ type Ok<Op> = Op extends {
56
56
  [K in keyof R]: K extends 200 | 201 | 202 ? JsonOf<R[K]> : never;
57
57
  }[keyof R] : never;
58
58
  export type OpenResponse = Ok<operations['postV1WorkspacesOpen']>;
59
- /** POST /v1/workspaces/{id}/resume: the held 200 (contracts §22.6) or the lifecycle 202. */
59
+ /** POST /v1/workspaces/{id}/resume: the held 200 or the lifecycle 202. */
60
60
  export type ResumeResponse = Ok<operations['postV1WorkspacesWorkspaceIdResume']>;
61
61
  /** What a resume request answered (0.9.0; `WorkspacesApi.requestResume`). */
62
62
  export interface ResumeAnswer {
@@ -95,7 +95,7 @@ export type PortalSession = Ok<operations['postApiV1OrganizationsOrganizationIdB
95
95
  export type InvoicePage = Ok<operations['getApiV1OrganizationsOrganizationIdBillingInvoices']>;
96
96
  export type Invoice = InvoicePage['data'][number];
97
97
  /**
98
- * A pending suspend-when-idle request (0.10.0; contracts §20.6): once the workspace has been idle for `after_seconds`
98
+ * A pending suspend-when-idle request (0.10.0): once the workspace has been idle for `after_seconds`
99
99
  * (counted from the later of its last work and `requested_at`), it is suspended; `not_before` = requested_at +
100
100
  * after_seconds is the earliest.
101
101
  */
@@ -103,7 +103,7 @@ export type SuspendRequest = components['schemas']['SuspendRequest'];
103
103
  /** POST /v1/workspaces/{id}/suspend-when-idle (202). */
104
104
  export type SuspendWhenIdleResponse = Ok<operations['postV1WorkspacesWorkspaceIdSuspendWhenIdle']>;
105
105
  export interface SuspendWhenIdleOptions {
106
- /** Seconds the workspace must stay idle before it is suspended: an integer from 30 to 3600 (the API refuses others with 422 validation_failed). */
106
+ /** Seconds the workspace must stay idle before it is suspended: an integer from 0 (as soon as it is idle) to 3600 (the API refuses others with 422 validation_failed). */
107
107
  afterSeconds: number;
108
108
  /** Replays the stored response for a repeated request (default: a fresh key per call, so transport retries replay). */
109
109
  idempotencyKey?: string;
@@ -121,7 +121,7 @@ export interface ShardfluxOptions {
121
121
  apiKey: string;
122
122
  /** Default https://api.shardflux.dev (override with `baseUrl`). */
123
123
  baseUrl?: string;
124
- /** Default: the runtime's fetch, with `Connection: close` on Node 26 (undici 8 keep-alive stalls; see defaultFetch in http.ts). */
124
+ /** Default: the runtime's fetch; on Node 26 every request uses a fresh connection (`Connection: close`) unless SHARDFLUX_HTTP_KEEPALIVE=1. */
125
125
  fetch?: typeof fetch;
126
126
  userAgent?: string;
127
127
  /** Per-request timeout (ms), default 30 s. */
@@ -136,7 +136,7 @@ export interface ShardfluxOptions {
136
136
  */
137
137
  onProgress?: ProgressListener;
138
138
  /**
139
- * The automatic version check (0.9.0; contracts §30.4): after the first successful API response of the process, a
139
+ * The automatic version check (0.9.0): after the first successful API response of the process, a
140
140
  * background GET /v1/client-versions (3 s timeout, errors swallowed) emits a `ShardfluxUpdateWarning` when this
141
141
  * package is outdated or unsupported. Default true (`@shardflux/sdk` at SDK_VERSION); tools built on the SDK pass
142
142
  * their own `{ package, version }` or `false`. `SHARDFLUX_NO_UPDATE_CHECK=1` or `NO_UPDATE_NOTIFIER=1` turn it off.
@@ -155,16 +155,16 @@ export interface ForkTarget {
155
155
  }
156
156
  export interface WaitOptions {
157
157
  /**
158
- * Give up waiting after this long (default 300 000 ms); the operation continues server side. A start waiting for
159
- * capacity (`capacity_pending`) does so until its deadline (`error.details.deadline_at`, 15 minutes after it was
160
- * created) and then fails with `capacity_unavailable` (retryable; nothing was started).
158
+ * Give up waiting after this long (default 300 000 ms); the operation continues server side. A queued start
159
+ * (`capacity_pending`) has a deadline (`error.details.deadline_at`, 15 minutes after it was created); past it, it
160
+ * fails with `capacity_unavailable` (retryable; nothing was started).
161
161
  */
162
162
  timeoutMs?: number;
163
163
  /** First poll delay (default 250 ms); doubles up to `maxPollIntervalMs` with jitter. Used when the server does not wait. */
164
164
  pollIntervalMs?: number;
165
165
  maxPollIntervalMs?: number;
166
166
  /**
167
- * Ask the server to hold each poll until the state changes (`Prefer: wait`, contracts §3; default true). A server
167
+ * Ask the server to hold each poll until the state changes (`Prefer: wait`; default true). A server
168
168
  * that does not wait answers at once and the SDK falls back to the backoff above.
169
169
  */
170
170
  serverWait?: boolean;
@@ -189,7 +189,7 @@ export interface OpenParams {
189
189
  */
190
190
  secrets?: string[];
191
191
  /**
192
- * The template version's text inputs `{NAME: value}` (0.7.0; contracts §24.3), put into the environment of every
192
+ * The template version's text inputs `{NAME: value}` (0.7.0), put into the environment of every
193
193
  * exec, terminal, start command and service. A new key stores each given value, else the declared default; an
194
194
  * existing key replaces them all (omitted leaves them unchanged). Secret inputs are not passed here: they bind the
195
195
  * stored secret of the same name. ShardfluxApiError 422 with details.reason `input_unknown` (an undeclared name),
@@ -204,7 +204,7 @@ export interface OpenParams {
204
204
  */
205
205
  lifetime?: WorkspaceLifetime;
206
206
  /**
207
- * `file_first` (0.9.0; contracts §29): the workspace is a versioned file tree with no VM between executions. It is
207
+ * `file_first` (0.9.0): the workspace is a versioned file tree with no VM between executions. It is
208
208
  * ready at once (no operation: the open answers with a tool token), never suspended, and runs commands as executions
209
209
  * (`workspace.executions.run()`): a fresh VM on the latest tree whose changed files become the next tree revision;
210
210
  * nothing else survives an execution. Needs a layered template version (409 `layout_unsupported` otherwise) and is
@@ -248,7 +248,7 @@ export interface FindByKeyOptions {
248
248
  signal?: AbortSignal;
249
249
  }
250
250
  /**
251
- * The workspace a key names (contracts §19.11): the live row (deleted_at null) when there is one, since at most one live
251
+ * The workspace a key names: the live row (deleted_at null) when there is one, since at most one live
252
252
  * workspace holds a key; otherwise the newest tombstone (ended sessions leave tombstones with the same key, and a
253
253
  * deleted persistent key keeps its tombstone). Null when no row has exactly this key. Rows need not be sorted.
254
254
  */
@@ -283,13 +283,13 @@ export declare class WorkspacesApi {
283
283
  open(params: OpenParams): Promise<Workspace>;
284
284
  /**
285
285
  * Waits for an operation: each GET /v1/operations/{id} asks the server to hold the response until the state changes
286
- * (`Prefer: wait`, at most 20 s, contracts §3), so completion is seen within one notification of the commit. A server
286
+ * (`Prefer: wait`, at most 20 s), so completion is seen within one notification of the commit. A server
287
287
  * that does not wait is polled with bounded exponential backoff (+-20 % jitter). Resolves when the operation
288
288
  * succeeds; throws OperationFailedError when it fails or is canceled, OperationTimeoutError after `timeoutMs` (the
289
289
  * operation keeps running and can be awaited again). Both errors carry the wait's `timing`; `onProgress` sees each
290
- * state change (queued, capacity_pending, running, with the server's reason) as it is observed. A start waiting in
291
- * capacity_pending gives up at its deadline (`deadlineAt` on the phase event) and fails with `capacity_unavailable`
292
- * (`err.retryable` true: nothing was started, retry later); the SDK does not retry it.
290
+ * state change (queued, capacity_pending, running, with the server's reason) as it is observed. A start in
291
+ * capacity_pending that passes its deadline (`deadlineAt` on the phase event) fails with `capacity_unavailable`
292
+ * (`err.retryable` true: nothing was started; send it again); the SDK does not retry it.
293
293
  */
294
294
  waitForOperation(operationId: string, opts?: WaitOptions): Promise<Operation>;
295
295
  /** One operation (GET /v1/operations/{id}); lifecycle operations stay pollable after a workspace is deleted. */
@@ -323,7 +323,7 @@ export declare class WorkspacesApi {
323
323
  suspend(workspaceId: string, opts?: LifecycleOptions): Promise<Operation>;
324
324
  /**
325
325
  * Resumes a suspended workspace. Resolves when the resume is requested; with `wait`, once the workspace runs. With
326
- * `wait` (0.9.0) the request is held by the server until the workspace runs (contracts §22.6: one request, timing phase
326
+ * `wait` (0.9.0) the request is held by the server until the workspace runs (one request, timing phase
327
327
  * `request` with reason `held`); a server that does not hold it answers at once and the operation is polled.
328
328
  * `serverWait: false` polls only. `agentLabel`/`tools` choose the tool token the held answer carries (attribution
329
329
  * only here; `workspace.resume()` keeps it). A workspace that is already running is ShardfluxApiError 409 `conflict`
@@ -333,7 +333,7 @@ export declare class WorkspacesApi {
333
333
  resume(workspaceId: string, opts?: ResumeOptions): Promise<Operation>;
334
334
  /**
335
335
  * One `POST /v1/workspaces/{id}/resume` (0.9.0), held for up to `waitS` seconds when that is at least 1 (`Prefer:
336
- * wait`, contracts §22.6), asking for the tool token of `agentLabel`/`tools`. `ready` only for a 200 the server says it
336
+ * wait`), asking for the tool token of `agentLabel`/`tools`. `ready` only for a 200 the server says it
337
337
  * held (`Preference-Applied`); every other answer is the operation to wait for, so a server without the held resume
338
338
  * works unchanged. Refusals (409 operation_in_progress, already_running without the hold, ...) throw as usual.
339
339
  * `Workspace.wake()` and `resume({ wait })` use it; most callers want those.
@@ -347,7 +347,7 @@ export declare class WorkspacesApi {
347
347
  label?: string;
348
348
  }): Promise<Operation>;
349
349
  /**
350
- * Suspends the workspace once it has been idle for `afterSeconds` (0.9.0; contracts §20.6): meant for the end of an
350
+ * Suspends the workspace once it has been idle for `afterSeconds` (0.9.0): meant for the end of an
351
351
  * agent turn, so the workspace stops using RAM soon after instead of waiting out its idle policy. The idle time
352
352
  * counts from the later of the workspace's last work and this request. A command still running, an attached exec or
353
353
  * terminal stream, or a keepalive postpones the suspend until `afterSeconds` after it ends; a tool call after the
@@ -357,7 +357,7 @@ export declare class WorkspacesApi {
357
357
  * Resolves with the recorded `suspendRequest`, or, when a suspend is already in progress, with that `operation` and
358
358
  * nothing recorded. Tool-call capture writes recorded before the call land first (a later write would count as the
359
359
  * next turn). Errors: ShardfluxApiError 409 with reason `not_running`, `operation_in_progress`, `session_lifetime` or
360
- * `workspace_deleted`; 422 `validation_failed` for `afterSeconds` outside 30..3600.
360
+ * `workspace_deleted`; 422 `validation_failed` for `afterSeconds` outside 0..3600.
361
361
  *
362
362
  * await cloud.workspaces.suspendWhenIdle(workspace.id, { afterSeconds: 60 });
363
363
  */
@@ -369,7 +369,7 @@ export declare class WorkspacesApi {
369
369
  */
370
370
  cancelSuspendWhenIdle(workspaceId: string): Promise<Workspace>;
371
371
  /**
372
- * Ends a session workspace now (contracts §19.11): the workspace is deleted exactly like delete() (ended_reason
372
+ * Ends a session workspace now: the workspace is deleted exactly like delete() (ended_reason
373
373
  * closed) and returns the `delete` operation (input.reason session_closed); the key then opens a NEW workspace.
374
374
  * Idempotent. A persistent workspace is ShardfluxApiError 409 (details.reason `not_session`): use
375
375
  * `workspace.close()`, which calls this only for sessions. With `wait`, resolves once the delete has finished.
@@ -382,7 +382,7 @@ export declare class WorkspacesApi {
382
382
  workspace: WorkspaceView;
383
383
  }>;
384
384
  /**
385
- * Resets a layered workspace to its template (contracts §19.12): every change in the workspace layer is wiped; key,
385
+ * Resets a layered workspace to its template: every change in the workspace layer is wiped; key,
386
386
  * id, template version, caps, secret bindings and volume attachments stay. Running: restarted on a blank layer
387
387
  * (processes are gone; old tool tokens get 409 stale_epoch and the SDK refreshes them). Suspended: stays suspended and
388
388
  * boots blank on the next resume. Returns the `reset` operation; its result names the recovery checkpoint (restorable
@@ -391,7 +391,7 @@ export declare class WorkspacesApi {
391
391
  reset(workspaceId: string, opts: WaitedLifecycleOptions): Promise<FinishedOperation>;
392
392
  reset(workspaceId: string, opts?: LifecycleOptions): Promise<Operation>;
393
393
  /**
394
- * Saves a layered workspace as the next version of an organization template (contracts §19.8). A running workspace is
394
+ * Saves a layered workspace as the next version of an organization template. A running workspace is
395
395
  * captured briefly (`operation`, layer_snapshot); poll `build` with templates.builds.waitForBuild. Owners/admins and
396
396
  * API keys with a tool permission only.
397
397
  */
@@ -409,7 +409,7 @@ export declare class WorkspacesApi {
409
409
  operation: Operation;
410
410
  workspace: Workspace;
411
411
  }>;
412
- /** The workspace's text inputs `{NAME: value}` (0.7.0; contracts §24.3). Secret inputs are bound secrets, never listed. */
412
+ /** The workspace's text inputs `{NAME: value}` (0.7.0). Secret inputs are bound secrets, never listed. */
413
413
  inputs(workspaceId: string): Promise<Record<string, string>>;
414
414
  operations(workspaceId: string, params?: {
415
415
  limit?: number;
@@ -454,17 +454,17 @@ export declare class Shardflux {
454
454
  readonly egress: EgressPolicyApi;
455
455
  /** Organization audit trail (owner/admin; API keys are refused with 403). */
456
456
  readonly audit: AuditApi;
457
- /** Shared volumes: persistent storage attached to workspaces at a mount path (contracts §15). */
457
+ /** Shared volumes: persistent storage attached to workspaces at a mount path. */
458
458
  readonly volumes: VolumesApi;
459
459
  constructor(opts: ShardfluxOptions);
460
460
  /** The authenticated principal (the API key, its organization and project). */
461
461
  me(): Promise<Me>;
462
462
  entitlements(organizationId: string): Promise<Entitlements>;
463
463
  /**
464
- * Send feedback straight to the Shardflux founder (0.9.0+; POST /v1/feedback), who reads every message. Use it while
465
- * you work, the moment something fails unexpectedly, an error or doc is confusing, something is missing or slow, or a
466
- * workaround was needed; short and specific beats polished, and `context.requestId` / `errorCode` let the founder find
467
- * the logs. `context.client` defaults to `shardflux-sdk-ts/<SDK_VERSION>`. Returns `{ id, receivedAt, duplicate }`
464
+ * Send feedback straight to the Shardflux team (0.9.0+; POST /v1/feedback), who read every message. Use it while you
465
+ * work, the moment something fails unexpectedly, an error or doc is unclear, an option is missing, or a workaround was
466
+ * needed, and when your user asks for a capability, an option or a smoother workflow; short and specific beats
467
+ * polished, and `context.requestId` / `errorCode` let the team find the logs. `context.client` defaults to `shardflux-sdk-ts/<SDK_VERSION>`. Returns `{ id, receivedAt, duplicate }`
468
468
  * (`duplicate`: the same message from this key within 24 hours; no second email). 429 `rate_limited` (with
469
469
  * `retryAfterSeconds`) and 422 `validation_failed` are ShardfluxApiErrors; the call is never retried.
470
470
  */
package/dist/client.js CHANGED
@@ -13,7 +13,7 @@ import { Trace, combineListeners, traced } from "./progress.js";
13
13
  import { CaptureRegistry } from "./capture.js";
14
14
  import { sendFeedback } from "./feedback.js";
15
15
  /**
16
- * The workspace a key names (contracts §19.11): the live row (deleted_at null) when there is one, since at most one live
16
+ * The workspace a key names: the live row (deleted_at null) when there is one, since at most one live
17
17
  * workspace holds a key; otherwise the newest tombstone (ended sessions leave tombstones with the same key, and a
18
18
  * deleted persistent key keeps its tombstone). Null when no row has exactly this key. Rows need not be sorted.
19
19
  */
@@ -61,7 +61,7 @@ function abortableSleep(sleep, ms, signal) {
61
61
  }
62
62
  export class WorkspacesApi {
63
63
  #ctx;
64
- /** The cell endpoint of the last tool token seen: an open pre-connects to it while the server works (contracts §22.3). */
64
+ /** The cell endpoint of the last tool token seen: an open pre-connects to it while the server works. */
65
65
  #cellHint = null;
66
66
  constructor(ctx) {
67
67
  this.#ctx = ctx;
@@ -108,7 +108,7 @@ export class WorkspacesApi {
108
108
  const started = Date.now();
109
109
  const timeoutMs = waitOpts?.timeoutMs ?? 300_000;
110
110
  if (waitOpts && waitOpts.serverWait !== false) {
111
- // Held open (contracts §22.3): the server answers once the operation is terminal (200 with the running workspace
111
+ // Held open: the server answers once the operation is terminal (200 with the running workspace
112
112
  // and a tool token) or the wait elapsed (202); a server without it answers 202 at once and the poll below runs.
113
113
  const s = Math.min(SERVER_WAIT_MAX_S, Math.floor(timeoutMs / 1000));
114
114
  if (s >= 1) {
@@ -188,13 +188,13 @@ export class WorkspacesApi {
188
188
  }
189
189
  /**
190
190
  * Waits for an operation: each GET /v1/operations/{id} asks the server to hold the response until the state changes
191
- * (`Prefer: wait`, at most 20 s, contracts §3), so completion is seen within one notification of the commit. A server
191
+ * (`Prefer: wait`, at most 20 s), so completion is seen within one notification of the commit. A server
192
192
  * that does not wait is polled with bounded exponential backoff (+-20 % jitter). Resolves when the operation
193
193
  * succeeds; throws OperationFailedError when it fails or is canceled, OperationTimeoutError after `timeoutMs` (the
194
194
  * operation keeps running and can be awaited again). Both errors carry the wait's `timing`; `onProgress` sees each
195
- * state change (queued, capacity_pending, running, with the server's reason) as it is observed. A start waiting in
196
- * capacity_pending gives up at its deadline (`deadlineAt` on the phase event) and fails with `capacity_unavailable`
197
- * (`err.retryable` true: nothing was started, retry later); the SDK does not retry it.
195
+ * state change (queued, capacity_pending, running, with the server's reason) as it is observed. A start in
196
+ * capacity_pending that passes its deadline (`deadlineAt` on the phase event) fails with `capacity_unavailable`
197
+ * (`err.retryable` true: nothing was started; send it again); the SDK does not retry it.
198
198
  */
199
199
  async waitForOperation(operationId, opts = {}) {
200
200
  const inherited = opts[TRACE];
@@ -379,7 +379,7 @@ export class WorkspacesApi {
379
379
  }
380
380
  /**
381
381
  * One `POST /v1/workspaces/{id}/resume` (0.9.0), held for up to `waitS` seconds when that is at least 1 (`Prefer:
382
- * wait`, contracts §22.6), asking for the tool token of `agentLabel`/`tools`. `ready` only for a 200 the server says it
382
+ * wait`), asking for the tool token of `agentLabel`/`tools`. `ready` only for a 200 the server says it
383
383
  * held (`Preference-Applied`); every other answer is the operation to wait for, so a server without the held resume
384
384
  * works unchanged. Refusals (409 operation_in_progress, already_running without the hold, ...) throw as usual.
385
385
  * `Workspace.wake()` and `resume({ wait })` use it; most callers want those.
@@ -419,7 +419,7 @@ export class WorkspacesApi {
419
419
  return this.#op('snapshot', workspaceId, opts.label === undefined ? {} : { label: opts.label }, opts);
420
420
  }
421
421
  /**
422
- * Suspends the workspace once it has been idle for `afterSeconds` (0.9.0; contracts §20.6): meant for the end of an
422
+ * Suspends the workspace once it has been idle for `afterSeconds` (0.9.0): meant for the end of an
423
423
  * agent turn, so the workspace stops using RAM soon after instead of waiting out its idle policy. The idle time
424
424
  * counts from the later of the workspace's last work and this request. A command still running, an attached exec or
425
425
  * terminal stream, or a keepalive postpones the suspend until `afterSeconds` after it ends; a tool call after the
@@ -429,7 +429,7 @@ export class WorkspacesApi {
429
429
  * Resolves with the recorded `suspendRequest`, or, when a suspend is already in progress, with that `operation` and
430
430
  * nothing recorded. Tool-call capture writes recorded before the call land first (a later write would count as the
431
431
  * next turn). Errors: ShardfluxApiError 409 with reason `not_running`, `operation_in_progress`, `session_lifetime` or
432
- * `workspace_deleted`; 422 `validation_failed` for `afterSeconds` outside 30..3600.
432
+ * `workspace_deleted`; 422 `validation_failed` for `afterSeconds` outside 0..3600.
433
433
  *
434
434
  * await cloud.workspaces.suspendWhenIdle(workspace.id, { afterSeconds: 60 });
435
435
  */
@@ -465,7 +465,7 @@ export class WorkspacesApi {
465
465
  return this.#op('reset', workspaceId, body, opts);
466
466
  }
467
467
  /**
468
- * Saves a layered workspace as the next version of an organization template (contracts §19.8). A running workspace is
468
+ * Saves a layered workspace as the next version of an organization template. A running workspace is
469
469
  * captured briefly (`operation`, layer_snapshot); poll `build` with templates.builds.waitForBuild. Owners/admins and
470
470
  * API keys with a tool permission only.
471
471
  */
@@ -488,7 +488,7 @@ export class WorkspacesApi {
488
488
  }, { settle: true });
489
489
  return { operation, workspace: copy };
490
490
  }
491
- /** The workspace's text inputs `{NAME: value}` (0.7.0; contracts §24.3). Secret inputs are bound secrets, never listed. */
491
+ /** The workspace's text inputs `{NAME: value}` (0.7.0). Secret inputs are bound secrets, never listed. */
492
492
  async inputs(workspaceId) {
493
493
  const body = await this.#http.json('GET', `/v1/workspaces/${encodeURIComponent(workspaceId)}/inputs`, {}, this.#auth);
494
494
  return body.inputs;
@@ -546,7 +546,7 @@ export class Shardflux {
546
546
  egress;
547
547
  /** Organization audit trail (owner/admin; API keys are refused with 403). */
548
548
  audit;
549
- /** Shared volumes: persistent storage attached to workspaces at a mount path (contracts §15). */
549
+ /** Shared volumes: persistent storage attached to workspaces at a mount path. */
550
550
  volumes;
551
551
  #ctx;
552
552
  constructor(opts) {
@@ -583,10 +583,10 @@ export class Shardflux {
583
583
  return this.#ctx.http.json('GET', `/v1/organizations/${encodeURIComponent(organizationId)}/entitlements`, {}, this.#ctx.authorization);
584
584
  }
585
585
  /**
586
- * Send feedback straight to the Shardflux founder (0.9.0+; POST /v1/feedback), who reads every message. Use it while
587
- * you work, the moment something fails unexpectedly, an error or doc is confusing, something is missing or slow, or a
588
- * workaround was needed; short and specific beats polished, and `context.requestId` / `errorCode` let the founder find
589
- * the logs. `context.client` defaults to `shardflux-sdk-ts/<SDK_VERSION>`. Returns `{ id, receivedAt, duplicate }`
586
+ * Send feedback straight to the Shardflux team (0.9.0+; POST /v1/feedback), who read every message. Use it while you
587
+ * work, the moment something fails unexpectedly, an error or doc is unclear, an option is missing, or a workaround was
588
+ * needed, and when your user asks for a capability, an option or a smoother workflow; short and specific beats
589
+ * polished, and `context.requestId` / `errorCode` let the team find the logs. `context.client` defaults to `shardflux-sdk-ts/<SDK_VERSION>`. Returns `{ id, receivedAt, duplicate }`
590
590
  * (`duplicate`: the same message from this key within 24 hours; no second email). 429 `rate_limited` (with
591
591
  * `retryAfterSeconds`) and 422 `validation_failed` are ShardfluxApiErrors; the call is never retried.
592
592
  */
package/dist/egress.d.ts CHANGED
@@ -50,7 +50,7 @@ export interface EgressPolicyVersion {
50
50
  created_at: string;
51
51
  }
52
52
  export interface EffectiveEgressPolicy {
53
- /** organization: an organization egress override (contracts §18) wins over every policy (mode deny_all, no version). */
53
+ /** organization: an organization egress override wins over every policy (mode deny_all, no version). */
54
54
  source: 'organization' | 'workspace' | 'project' | 'platform_default';
55
55
  policy_version_id: string | null;
56
56
  policy_version: number | null;
@@ -60,7 +60,7 @@ export interface EffectiveEgressPolicy {
60
60
  policy_sha256: string;
61
61
  }
62
62
  /**
63
- * Active organization egress override (contracts §18): the organization used its whole outbound transfer allowance,
63
+ * Active organization egress override: the organization used its whole outbound transfer allowance,
64
64
  * so outbound internet traffic of every workspace is blocked until `lifts_at` (period end) or an upgrade/purchase.
65
65
  * Stored policies are kept and apply again when it lifts.
66
66
  */
@@ -123,7 +123,7 @@ export interface WorkspaceEgressPolicy {
123
123
  organization_override: OrganizationEgressOverride | null;
124
124
  enforcement: EgressEnforcement;
125
125
  /**
126
- * The template version's network ceiling (0.7.0; contracts §24.3 `defaults.egress`), or null. The host enforces
126
+ * The template version's network ceiling (0.7.0 `defaults.egress`), or null. The host enforces
127
127
  * `effective` intersected with it; a workspace policy it would narrow is refused with 422 egress_widening.
128
128
  */
129
129
  template_egress: {