@shardflux/cli 0.6.2 → 0.8.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.
- package/CHANGELOG.md +96 -0
- package/README.md +121 -10
- package/dist/args.d.ts +1 -1
- package/dist/args.js +76 -7
- package/dist/commands.js +284 -10
- package/dist/errors.d.ts +11 -2
- package/dist/errors.js +28 -7
- package/dist/format.d.ts +16 -6
- package/dist/format.js +93 -1
- package/dist/http.d.ts +1 -10
- package/dist/http.js +6 -18
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/main.js +42 -6
- package/dist/template-yaml.js +3 -0
- package/dist/timing.d.ts +12 -0
- package/dist/timing.js +48 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,79 @@
|
|
|
3
3
|
Every command and option the README shows is available from the version named here. Breaking changes ship in minor
|
|
4
4
|
releases and are marked **Breaking**.
|
|
5
5
|
|
|
6
|
+
## 0.8.0 (not yet published)
|
|
7
|
+
|
|
8
|
+
Needs `@shardflux/sdk` 0.13.0 or later.
|
|
9
|
+
|
|
10
|
+
### Elastic memory
|
|
11
|
+
|
|
12
|
+
- `shard ws open` and `shard ws fork`: `--allocation-mode fixed|elastic` and `--memory-held <mib>` (elastic only; a
|
|
13
|
+
usage error otherwise), sent with the caps. Caps flags replace the stored caps; no caps flag keeps the stored layout.
|
|
14
|
+
- `shard ws get` (and a ready `ws open`) prints a `memory` line: `fixed 4096 MiB`, or `elastic: promised 8192 MiB,
|
|
15
|
+
held 1024 MiB, plugged +2048 MiB` (`- (not running)` without a live allocation). `caps` shows `allocation_mode` and
|
|
16
|
+
`memory_mib_held`.
|
|
17
|
+
- `shard ws exec -v` prints `memory grow partial 1024 -> 3072 of 4096 MiB in 175 ms` on stderr when the command's
|
|
18
|
+
start waited for a grow; `--json` adds `memory_grow`. Without a grow nothing changes.
|
|
19
|
+
|
|
20
|
+
### Burst execution
|
|
21
|
+
|
|
22
|
+
- `shard ws exec --burst [--burst-vcpus N] [--burst-memory MIB]` runs the command on a larger, short-lived burst VM
|
|
23
|
+
and applies its file changes back.
|
|
24
|
+
`-v` prints a `burst` line (size, method, applied changes, leftover processes killed, overhead) on stderr; `--json`
|
|
25
|
+
adds `burst`. The sizes without `--burst`, out of range, or `--burst` with `--stdin`, are usage errors (exit 2);
|
|
26
|
+
`--burst` on a file-first workspace too.
|
|
27
|
+
- Ctrl-C does not cancel a burst (it cannot be canceled). A `burst_apply_failed` error names the exec session on
|
|
28
|
+
stderr.
|
|
29
|
+
|
|
30
|
+
### Background commands
|
|
31
|
+
|
|
32
|
+
- `shard ws exec-start --timeout <duration>`: kill the command after this long (parsed like `shard ws exec --timeout`;
|
|
33
|
+
none unless set). Without `--json` it names the commands that read and stop the session on stderr.
|
|
34
|
+
- `shard ws exec-read <id|key> <session-id> [--follow]`: the session's stdout and stderr from the start. An ended
|
|
35
|
+
session exits with the command's exit code (124 timed out, 128+N killed by signal N), one that still runs exits 5
|
|
36
|
+
with the command that follows it. `--follow` streams until the command exits, resuming from byte offsets after a
|
|
37
|
+
dropped connection; Ctrl-C stops following and the command keeps running. `--json` prints one object (`session_id`,
|
|
38
|
+
`state`, `exit_code`, `term_signal`, `timed_out`, `canceled`, `stdout`, `stderr`, `truncated`, `reconnects`).
|
|
39
|
+
A session that could not start exits 6 with the workspace's reason, as `shard ws exec` does.
|
|
40
|
+
- `shard ws exec-cancel <id|key> <session-id> [--grace <duration>]`: SIGTERM, then SIGKILL after the grace (default
|
|
41
|
+
5s, at most 60s). Prints `exec session <id>: canceled (signal 15)` (`--json`: the session).
|
|
42
|
+
|
|
43
|
+
### Suspend by id
|
|
44
|
+
|
|
45
|
+
- `shard ws suspend <id>` sends the suspend straight to the workspace, without first fetching it: one request fewer.
|
|
46
|
+
The line it prints names the id you gave (`Suspending <id>: operation ...`); with a key it is unchanged
|
|
47
|
+
(`Suspending <key> (<id>): ...`). A UUID that is no workspace id is still tried as a key.
|
|
48
|
+
|
|
49
|
+
### Held fork
|
|
50
|
+
|
|
51
|
+
- `shard ws fork --wait` gets the running copy and its tool token in the fork request itself when the API holds the
|
|
52
|
+
fork (SDK 0.13.0), without the follow-up operation poll and copy refresh. Against an API that does not, it polls as
|
|
53
|
+
before. `shard ws fork` without `--wait` is unchanged.
|
|
54
|
+
|
|
55
|
+
### Exec start and output in one request
|
|
56
|
+
|
|
57
|
+
- `shard ws exec` starts the command and streams its output in one request on cells that support it (SDK 0.13.0);
|
|
58
|
+
output still resumes from byte offsets after a dropped connection, and the command never runs twice.
|
|
59
|
+
|
|
60
|
+
### Immutable paths
|
|
61
|
+
|
|
62
|
+
A template may declare directories as `immutable`: every workspace of it mounts them read-only from the template's
|
|
63
|
+
newest published version.
|
|
64
|
+
|
|
65
|
+
- `shard templates get`: an `IMMUTABLE PATHS` column with each version's paths and image size
|
|
66
|
+
(`/opt/acme, /srv/tools (128.0 MiB)`), shown when a version declares any.
|
|
67
|
+
- `shard ws get` (and a ready `ws open`): `immutable paths v2 (mounted read-only)`, the template version whose
|
|
68
|
+
immutable paths the workspace has mounted.
|
|
69
|
+
- `shard templates build` sends template.yaml's `immutable` list; `shard templates builds get` (and a build's output)
|
|
70
|
+
prints `immutable paths`, and for a build that failed on them a `fix` line (`immutable_path_missing`: make the path a
|
|
71
|
+
directory in the build; `immutable_image_too_large`). `shard templates export` writes the list back.
|
|
72
|
+
`shard templates init` describes `immutable` in a comment.
|
|
73
|
+
- Hints for the refusals: `immutable_path_removed` names the paths to add back, `immutable_paths_unsupported_base` the
|
|
74
|
+
base to build on, `invalid_path` the `immutable[<i>]` entry to fix (exit 2), and a write under an immutable path
|
|
75
|
+
(`read_only_path`, 409 from the workspace, exit 1) says where to change it.
|
|
76
|
+
- **Breaking:** `--json` output no longer carries `update_policy`: the API removed the update policy (it was always
|
|
77
|
+
`pinned`).
|
|
78
|
+
|
|
6
79
|
## 0.6.2
|
|
7
80
|
|
|
8
81
|
Needs `@shardflux/sdk` 0.11.1 or later.
|
|
@@ -38,6 +111,29 @@ New organizations can start on a trial: 60 days at Developer limits, no card. Th
|
|
|
38
111
|
- An interrupted file-first `ws exec` says `(an execution runs to completion)`; `mode_not_available` drops "yet";
|
|
39
112
|
`--open` no longer says "best effort"; `templates init --help` no longer names an internal document.
|
|
40
113
|
|
|
114
|
+
## 0.7.0 (release candidate)
|
|
115
|
+
|
|
116
|
+
Completed exec output streams are drained before releasing their HTTP connections, with a bounded cleanup if a peer does not close.
|
|
117
|
+
|
|
118
|
+
Uses SDK 0.12.0 and its pooled transport. Adds --labels/--idle-policy to open, --labels to list, ws labels, ws idle, ws exec-start --stdin-open and ws exec-input --offset. Protocol-error JSON includes source. Resume recovers failed workspaces; completed deletion permits key reuse.
|
|
119
|
+
|
|
120
|
+
Requires the QM integration backend release for labels, failed recovery, key reuse and pipe stdin. No production deployment has occurred from this branch.
|
|
121
|
+
|
|
122
|
+
### Instant suspend: durable storage
|
|
123
|
+
|
|
124
|
+
- `shard ws suspend --wait` still returns when the suspend succeeds (sealed on its host); a finished suspend or fork
|
|
125
|
+
now prints `durable: yes (<n> ms after the suspend)` or `durable: in progress ...` when the result says so.
|
|
126
|
+
- `shard ws suspend --durable`: waits until `result.durable` is true (implies `--wait`, shares `--timeout`). A copy
|
|
127
|
+
that cannot be made exits 6 with code `durability_lost` (operation id, `details.state` `lost`, `details.reason`); a
|
|
128
|
+
timeout exits 5 with `details.durable` false and `details.state` `pending`. `--durable` with `--when-idle` or
|
|
129
|
+
`--cancel-when-idle` is a usage error.
|
|
130
|
+
- `shard operations wait <id> --durable`, and a `durable` line in `operations get|wait` for suspends and forks.
|
|
131
|
+
- `--timing --json`: `server` gains `durable`, `suspend_path`, `durability` and `lost_suspend`.
|
|
132
|
+
- A resume (or a command's wake) whose result carries `lost_suspend` prints a note on stderr naming the restored
|
|
133
|
+
checkpoint and its time.
|
|
134
|
+
- A suspend-when-idle canceled `workspace_active` says the workspace was in use and keeps running.
|
|
135
|
+
- The `ws suspend` summary no longer says "durable checkpoint".
|
|
136
|
+
|
|
41
137
|
## 0.6.1
|
|
42
138
|
|
|
43
139
|
Needs `@shardflux/sdk` 0.11.0 or later.
|
package/README.md
CHANGED
|
@@ -374,11 +374,12 @@ shows the status; `shard version --check` asks now (`--json`: `{"cli", "sdk", "u
|
|
|
374
374
|
| `version [--check]` | Print the CLI and SDK versions and the update status (`--check` asks the API now). |
|
|
375
375
|
| `usage [--org <id>] [--estimate \| --series \| --workspace <id\|key>] [--from T] [--to T] [--granularity hour\|day] [--meter M]` | Usage summary for the current period: plan, meters and allowances. `--estimate`: the bill so far and projected allowance use; `--series`: usage over time; `--workspace`: one workspace's usage over time (0.5.0+). The summary includes the [overage](#usage-and-overage) block (0.5.1+). |
|
|
376
376
|
| `feedback [--category C] [--workspace W] [--request-id ID] [--error-code CODE] [--command TEXT] [--from-file F\|-] <message...>` | Send feedback straight to the Shardflux team (0.5.0+). See [Feedback](#feedback-agents-use-this-while-you-work). |
|
|
377
|
-
| `workspaces open <key> --template <slug> [--secret NAME]... [--input NAME=value]... [--input-file F] [--lifetime persistent\|session] [--mode processful\|file-first] [--cpu-millis N --memory-mib N --disk-gib N] [--no-wait] [--timeout 5m] [--timing]` | Open by key. Creates the workspace on first use and reconnects or resumes it afterwards, never resetting it. Waits until it is ready (the template's start commands and services included) unless you pass `--no-wait`. `--secret` binds secret names (replacing the binding of an existing workspace). `--input` (0.4.0+) passes the template's text inputs (replacing those of an existing workspace); `--input-file` reads `NAME=value` lines or a JSON object. `--lifetime session`: the workspace is discarded when the session ends (`workspaces close` or the idle timeout), and the key then opens a new workspace. `--mode file-first` (0.5.0+) opens a [file-first workspace](#file-first-workspaces); the default is processful for a new key and the stored mode for an existing one. |
|
|
377
|
+
| `workspaces open <key> --template <slug> [--secret NAME]... [--input NAME=value]... [--input-file F] [--lifetime persistent\|session] [--mode processful\|file-first] [--cpu-millis N --memory-mib N --disk-gib N] [--allocation-mode fixed\|elastic] [--memory-held N] [--no-wait] [--timeout 5m] [--timing]` | Open by key. Creates the workspace on first use and reconnects or resumes it afterwards, never resetting it. Waits until it is ready (the template's start commands and services included) unless you pass `--no-wait`. `--secret` binds secret names (replacing the binding of an existing workspace). `--input` (0.4.0+) passes the template's text inputs (replacing those of an existing workspace); `--input-file` reads `NAME=value` lines or a JSON object. `--lifetime session`: the workspace is discarded when the session ends (`workspaces close` or the idle timeout), and the key then opens a new workspace. `--mode file-first` (0.5.0+) opens a [file-first workspace](#file-first-workspaces); the default is processful for a new key and the stored mode for an existing one. `--allocation-mode elastic` (0.8.0+): [elastic memory](#elastic-memory-080). |
|
|
378
378
|
| `workspaces list [--state S] [--prefix P] [--lifetime persistent\|session\|any] [--purpose standard\|template_draft\|template_test\|any] [--include-deleted] [--all] [--limit N] [--cursor C]` | One page, or every page with `--all`. The next cursor is printed on stderr. By default only persistent standard workspaces are listed. A file-first workspace's state reads `running (file-first)` (0.5.0+). |
|
|
379
|
-
| `workspaces get <id\|key>` | One workspace (deleted ones included), with the startup of its template's start commands and services (0.4.0+): a failed step shows its exit code, reason and output tail. Its mode, and a file-first workspace's tree revision (0.5.0+). |
|
|
379
|
+
| `workspaces get <id\|key>` | One workspace (deleted ones included), with the startup of its template's start commands and services (0.4.0+): a failed step shows its exit code, reason and output tail. Its mode, and a file-first workspace's tree revision (0.5.0+). Its memory (0.8.0+): `fixed 4096 MiB`, or `elastic: promised …, held …, plugged +… MiB`. The template version whose [immutable paths](#immutable-paths-080) it has mounted (0.8.0+): `immutable paths v3 (mounted read-only)`. |
|
|
380
380
|
| `workspaces inputs <id\|key>` | The workspace's text inputs (0.4.0+). |
|
|
381
|
-
| `workspaces exec <id\|key> [--cwd D] [--env K=V]... [--timeout T] [--stdin F\|-] [-v] [--execution-id ID] [--output-limit N] -- <cmd> [args...]` | Runs argv with no shell. Output is streamed and resumes from byte offsets after dropped connections. `shard` exits with the command's exit code. Ctrl-C cancels the command. `-v` (0.5.0+) then prints the session id and exit status on stderr. `--cwd` is an absolute path (default `/home/user`); a relative one is refused (`invalid_cwd`, exit 2). A command that could not start (a `--cwd` that is not a directory, a program not on `PATH`) exits 6 with the workspace's reason and a hint (0.5.1+; before, it exited 1 with no output). On a file-first workspace (0.5.0+) the command runs as an execution instead: see [File-first workspaces](#file-first-workspaces). |
|
|
381
|
+
| `workspaces exec <id\|key> [--cwd D] [--env K=V]... [--timeout T] [--stdin F\|-] [-v] [--execution-id ID] [--output-limit N] [--burst [--burst-vcpus N] [--burst-memory MIB]] -- <cmd> [args...]` | Runs argv with no shell. Output is streamed (in the start request itself, 0.8.0+) and resumes from byte offsets after dropped connections. `shard` exits with the command's exit code. Ctrl-C cancels the command. `-v` (0.5.0+) then prints the session id and exit status on stderr, and the memory grow the command waited for on an elastic workspace (0.8.0+; `--json`: `memory_grow`). `--cwd` is an absolute path (default `/home/user`); a relative one is refused (`invalid_cwd`, exit 2). A command that could not start (a `--cwd` that is not a directory, a program not on `PATH`) exits 6 with the workspace's reason and a hint (0.5.1+; before, it exited 1 with no output). On a file-first workspace (0.5.0+) the command runs as an execution instead: see [File-first workspaces](#file-first-workspaces). `--burst` (0.8.0+): [burst execution](#burst-execution-080). |
|
|
382
|
+
| `workspaces exec-start <id\|key> [--session-id ID] [--cwd D] [--timeout T] [--stdin-open] -- <cmd> [args...]`, `workspaces exec-read <id\|key> <session-id> [--follow]`, `workspaces exec-cancel <id\|key> <session-id> [--grace D]` | Background commands (0.8.0+): start a command and return at once, read its output and state (`--follow` streams it to its exit and exits with its code; while it runs `exec-read` exits 5), stop it. See [Background commands](#background-commands-080). |
|
|
382
383
|
| `executions get <id\|key> <execution-id> [--wait D]` | The result of a file-first workspace's execution (0.5.0+): its output, then what ran. Exits with the command's code, 6 if the execution failed or was lost, 5 while it still runs. |
|
|
383
384
|
| `files read <id\|key> <path> [--out F]` | Raw bytes to stdout, or to a local file. |
|
|
384
385
|
| `files write <id\|key> <path> [--from F\|-] [--append] [--no-parents] [--if-revision N]` | Atomic write. The default source is stdin. `--if-revision` (0.5.0+): file-first workspaces only, see [Tree revisions](#tree-revisions). |
|
|
@@ -387,9 +388,10 @@ shows the status; `shard version --check` asks now (`--json`: `{"cli", "sdk", "u
|
|
|
387
388
|
| `files search <id\|key> <path> <pattern> [--regex] [-i\|--ignore-case] [--include G]... [--exclude G]... [--max N]` | Search file contents under a directory (or in one file; gitignore-style globs): `path:line:column: text` per match (0.5.0+). |
|
|
388
389
|
| `files patch <id\|key> <path> (--old T --new T)... [--replace-all] \| --content-file F\|- [--expected-revision R] [--if-revision N]` | Replace exact text (each `--old` must occur once unless `--replace-all`), or the whole content, atomically; `R` is a revision from `files stat --revision` or `absent` (0.5.0+). `--if-revision` (0.5.0+): file-first workspaces only. |
|
|
389
390
|
| `workspaces suspend\|resume <id\|key> [--wait] [--timeout T] [--timing]` | Lifecycle operation. Returns immediately unless you pass `--wait`. |
|
|
391
|
+
| `workspaces suspend <id\|key> --durable [--timeout T]` | (0.7.0+) Suspend and wait until the copy is in durable storage. See "Durable storage". |
|
|
390
392
|
| `workspaces suspend <id\|key> --when-idle D` / `--cancel-when-idle` | (0.5.1+) Suspend once the workspace has been idle for `D` (0 to 1h; `0` = as soon as it is idle, 0.6.1+), or cancel that. See "Suspend when idle". |
|
|
391
|
-
| `workspaces fork <id\|key> <new-key> [caps] [--wait]` | Fork into a new key. |
|
|
392
|
-
| `workspaces delete <id\|key> --yes [--wait]` | Delete the workspace. Tool access ends at once.
|
|
393
|
+
| `workspaces fork <id\|key> <new-key> [caps] [--allocation-mode fixed\|elastic] [--memory-held N] [--wait]` | Fork into a new key. Without caps the fork keeps the source's caps and memory allocation (0.8.0+). With `--wait` the API holds the fork until the copy runs and returns it ready in the same request (0.8.0+; `--timing` shows one `request` phase marked `(held)`). |
|
|
394
|
+
| `workspaces delete <id\|key> --yes [--wait]` | Delete the workspace. Tool access ends at once. After deletion finishes, the key can open a new workspace ID. |
|
|
393
395
|
| `workspaces close <id\|key> [--wait]` | End a session workspace now: it is deleted, and the key then opens a new workspace. A persistent workspace is refused (`not_session`). |
|
|
394
396
|
| `workspaces reset <id\|key> --yes [--wait]` | Layered workspaces: wipe every change and restart on the template. The previous state stays restorable for 7 days. |
|
|
395
397
|
| `workspaces save-as-template <id\|key> --template <slug> [--display-name N] [--description T] [--checkpoint ID] [--default-lifetime L] [--default-idle-timeout D] [--acknowledge PATH]... [--no-auto-publish] [--wait]` | Save a layered workspace as the next version of an organization template. `--wait` follows the build. |
|
|
@@ -403,7 +405,7 @@ shows the status; `shard version --check` asks now (`--json`: `{"cli", "sdk", "u
|
|
|
403
405
|
| `secrets versions <id\|NAME>`, `secrets delete <id\|NAME> --yes`, `secrets access-log <id\|NAME>` | Versions, deletion (also removes the name from every workspace binding), and the access log. |
|
|
404
406
|
| `operations list <id\|key> [--state S] [--kind K]`, `operations get <op>`, `operations wait <op> [--timeout T] [--timing]` | Operations. |
|
|
405
407
|
| `templates list [--owner platform\|organization] [--include-archived] [--all]` | Templates the project can open, with their open version, layouts, file list state and draft. |
|
|
406
|
-
| `templates get <slug> [--owner O] [--include-archived]` | One template (0.4.0+): its versions, what open resolves to, and the open version's settings (env, inputs, start commands, services, defaults). |
|
|
408
|
+
| `templates get <slug> [--owner O] [--include-archived]` | One template (0.4.0+): its versions, what open resolves to, and the open version's settings (env, inputs, start commands, services, defaults). Each version's [immutable paths](#immutable-paths-080) and their image size (0.8.0+). |
|
|
407
409
|
| `templates init --base <slug[@version]> [--out F] [--force]` | Write a starter `template.yaml` on a base (0.4.0+). |
|
|
408
410
|
| `templates build <file> [--slug S] [--display-name N] [--description T] [--publish] [--acknowledge PATH]... [--wait] [--timeout 30m] [--timing]` | Build a template from `template.yaml` (0.4.0+): local files and folders are uploaded, then the build is created. See [Build a template](#build-a-template-from-templateyaml). |
|
|
409
411
|
| `templates export <slug>@<version> [--out F] [--force]` | The `template.yaml` a version was built from, ready to build again (0.4.0+). |
|
|
@@ -474,6 +476,30 @@ settings:
|
|
|
474
476
|
- A file `shard` cannot read or pack (a symlink that leaves the folder, a device) is refused before any request (exit
|
|
475
477
|
2). The API's refusals (`upload_missing`, `language_unavailable`, `invalid_settings`, ...) exit 2 with the reason.
|
|
476
478
|
|
|
479
|
+
### Immutable paths (0.8.0+)
|
|
480
|
+
|
|
481
|
+
Directories listed under `immutable` follow the template: every workspace of it mounts them read-only from the
|
|
482
|
+
template's newest published version, picked up at its next cold boot or resume. Ship tools, models or data there and
|
|
483
|
+
existing workspaces get each new version; everything else in a workspace stays its own.
|
|
484
|
+
|
|
485
|
+
```yaml
|
|
486
|
+
immutable: [/opt/acme]
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
```sh
|
|
490
|
+
shard templates get acme-dev
|
|
491
|
+
# VERSION STATE SOURCE LAYOUTS IMMUTABLE PATHS CREATED DESCRIPTION
|
|
492
|
+
# v2 * published recipe layered /opt/acme (96.0 MiB) 2026-10-01 03:14:52Z tools 2.4
|
|
493
|
+
shard ws get acme/main
|
|
494
|
+
# template acme-dev v1 (<version id>)
|
|
495
|
+
# immutable paths v2 (mounted read-only)
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
A template.yaml without `immutable` keeps the list of the template's open version, and a new version keeps every path
|
|
499
|
+
of it (`immutable_path_removed` names the ones to add back). `shard templates builds get` lists a build's immutable
|
|
500
|
+
paths; `shard templates export` writes them back into template.yaml. A write under an immutable path
|
|
501
|
+
(`shard files write`) exits 1 with `read_only_path` and a hint.
|
|
502
|
+
|
|
477
503
|
## File-first workspaces
|
|
478
504
|
|
|
479
505
|
(0.5.0+) A file-first workspace has no VM between commands. Its state is a versioned file tree under `/home/user`.
|
|
@@ -616,6 +642,53 @@ shard ws suspend acme/demo --cancel-when-idle
|
|
|
616
642
|
workspace that is not running is refused with `conflict` (`not_running`, exit 1), and a file-first workspace (never
|
|
617
643
|
suspended) with `not_supported_for_mode` (exit 1).
|
|
618
644
|
|
|
645
|
+
## Elastic memory (0.8.0+)
|
|
646
|
+
|
|
647
|
+
Give a workspace a large memory promise while it holds only what it uses. It idles at `--memory-held` (default
|
|
648
|
+
1024 MiB) and grows before each command starts, so builds and test runners see the memory they need from their first
|
|
649
|
+
instruction.
|
|
650
|
+
|
|
651
|
+
```sh
|
|
652
|
+
shard ws open acme/demo --template python-node-browser --memory-mib 8192 --allocation-mode elastic
|
|
653
|
+
shard ws get acme/demo # memory elastic: promised 8192 MiB, held 1024 MiB, plugged +3072 MiB
|
|
654
|
+
shard ws exec acme/demo -v -- npm test # memory grow delivered 1024 -> 4096 MiB in 175 ms
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
The layout takes effect at the workspace's next start. `--json` output carries `memory` on the workspace and
|
|
658
|
+
`memory_grow` on a command that grew it.
|
|
659
|
+
|
|
660
|
+
## Burst execution (0.8.0+)
|
|
661
|
+
|
|
662
|
+
Run one heavy command, such as a cold build or a full test suite, on a larger VM without resizing the workspace:
|
|
663
|
+
`--burst` runs it on a short-lived burst VM over a copy of the workspace and applies its file changes back when it
|
|
664
|
+
exits. Output streams as usual and `shard` exits with the command's exit code.
|
|
665
|
+
|
|
666
|
+
```sh
|
|
667
|
+
shard ws exec acme/demo --burst --burst-vcpus 16 -v -- bash -lc "cd app && go build ./..."
|
|
668
|
+
# burst local 16 vCPU / 8192 MiB (layer); applied 3 files, 1 dirs, 1 removed, 40960 bytes; overhead 641 ms
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
`--burst-vcpus` and `--burst-memory` size the burst VM (default 8 vCPU and 8192 MiB within the plan's
|
|
672
|
+
per-workspace limits); `--json` adds `burst` to the result.
|
|
673
|
+
|
|
674
|
+
## Background commands (0.8.0+)
|
|
675
|
+
|
|
676
|
+
A long command (a build, a test suite, a training run, a server) can run in the background of a processful workspace
|
|
677
|
+
while you or your agent do other work:
|
|
678
|
+
|
|
679
|
+
```sh
|
|
680
|
+
shard ws exec-start acme/demo --session-id build-1 --timeout 2h -- bash -lc "make -C /home/user/app"
|
|
681
|
+
shard ws exec-read acme/demo build-1 # the output so far; exit 5 while it runs
|
|
682
|
+
shard ws exec-read acme/demo build-1 --follow # stream to the end; exits with the command's exit code
|
|
683
|
+
shard ws exec-cancel acme/demo build-1 --grace 10s
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
- `--timeout` is the longest the command may run; the workspace stays awake until it ends or that time passes.
|
|
687
|
+
- `exec-read` prints stdout and stderr from the start. `--follow` resumes from byte offsets after a dropped
|
|
688
|
+
connection; Ctrl-C stops following and the command keeps running. `--json` prints one object with the state, exit
|
|
689
|
+
code and output.
|
|
690
|
+
- `exec-cancel` sends SIGTERM, then SIGKILL after `--grace` (default 5s, at most 60s).
|
|
691
|
+
|
|
619
692
|
## Start deadlines
|
|
620
693
|
|
|
621
694
|
A queued open, resume or fork (`capacity_pending`) has a deadline 15 minutes after it was created.
|
|
@@ -787,16 +860,54 @@ printf %s "$NEW_KEY" | shard secrets rotate OPENAI_API_KEY
|
|
|
787
860
|
| 2 | usage error: bad arguments, or input the API rejected as `validation_failed` |
|
|
788
861
|
| 3 | not found: workspace, operation or route |
|
|
789
862
|
| 4 | authentication or authorization: missing, malformed, revoked or insufficient key or session; `step_up_required` (run `shard auth step-up`), `mfa_required` (a sign-in waiting for its code), `email_unverified`, `invalid_credentials` |
|
|
790
|
-
| 5 | timeout: waiting gave up (`--timeout`, or `--wake-timeout` while waking a workspace); the operation continues server side (`shard operations wait <id>`), up to a queued start's 15-minute deadline. `executions get` (0.5.0+): the execution is still queued or running. `billing upgrade --wait` (0.5.0+): nobody paid in time (the checkout stays open) |
|
|
863
|
+
| 5 | timeout: waiting gave up (`--timeout`, or `--wake-timeout` while waking a workspace); the operation continues server side (`shard operations wait <id>`), up to a queued start's 15-minute deadline. `executions get` (0.5.0+): the execution is still queued or running. `ws exec-read` (0.8.0+): the background command still runs. `billing upgrade --wait` (0.5.0+): nobody paid in time (the checkout stays open) |
|
|
791
864
|
| 6 | the awaited operation ended `failed` or `canceled` (also a resume or open that failed while waking a workspace). `retryable=true` in the error means a retry can succeed (`capacity_unavailable`). Also a file-first execution that ended `failed` or `lost` (0.5.0+): nothing was published. `exec` (0.5.1+): the command could not start (`exec_failed_to_start`). `billing upgrade --wait` (0.5.0+): the checkout expired or was canceled (`checkout_ended`) |
|
|
792
865
|
| 130 | interrupted (Ctrl-C). Waits stop at once, and exec sends a cancel to the session. A file-first execution runs to completion, and the error names the `shard executions get` command for its result. |
|
|
793
|
-
| exec, executions get | the command's own code: 124 if it timed out, 128+N if killed by signal N. Failures before the command ran use the codes above; use `--json` to tell them apart. |
|
|
866
|
+
| exec, executions get, ws exec-read | the command's own code: 124 if it timed out, 128+N if killed by signal N. Failures before the command ran use the codes above; use `--json` to tell them apart. |
|
|
867
|
+
|
|
868
|
+
## Durable storage (0.7.0+)
|
|
869
|
+
|
|
870
|
+
`shard ws suspend --wait` returns as soon as the workspace is sealed on its host, typically in a few hundred ms, and
|
|
871
|
+
its RAM and CPU are released then. The copy lands in durable storage right after, typically within a second:
|
|
872
|
+
|
|
873
|
+
```sh
|
|
874
|
+
shard ws suspend acme/demo --wait
|
|
875
|
+
# Suspending acme/demo (<id>): operation <op> suspend succeeded
|
|
876
|
+
# durable: in progress, typically within a second (wait with: shard operations wait <op> --durable)
|
|
877
|
+
shard ws suspend acme/demo --durable # returns once it is durable: "durable: yes (435 ms after the suspend)"
|
|
878
|
+
shard operations wait <op> --durable # the same for a suspend or fork you already started
|
|
879
|
+
```
|
|
880
|
+
|
|
881
|
+
- `--durable` implies `--wait` and shares its `--timeout`.
|
|
882
|
+
- `--json` prints the operation as the API returns it: `result.durable` and `result.durability` (`state`
|
|
883
|
+
`pending` or `durable`, `local_commit_at`, `durable_at`, ...). `--timing` adds `durable`, `suspend_path` and
|
|
884
|
+
`durability` to `server`.
|
|
885
|
+
- `operations get|wait` show a `durable` line for suspends and forks. A fork of a running workspace reports its copy the
|
|
886
|
+
same way.
|
|
887
|
+
- The exit codes and errors of `--durable` are in the CLI reference on docs.shardflux.dev.
|
|
794
888
|
|
|
795
889
|
## HTTP connections
|
|
796
890
|
|
|
797
|
-
|
|
798
|
-
connections.
|
|
891
|
+
`shard` 0.7.0 uses the SDK’s pooled HTTP/1.1 transport on Node 26. Custom fetch is preserved. `SHARDFLUX_HTTP_KEEPALIVE=0` forces connection closure for diagnosis; `=1` opts into native pooling.
|
|
799
892
|
|
|
800
893
|
## License
|
|
801
894
|
|
|
802
895
|
Apache-2.0
|
|
896
|
+
|
|
897
|
+
|
|
898
|
+
## Integration controls (0.7.0+)
|
|
899
|
+
|
|
900
|
+
```sh
|
|
901
|
+
shard ws open qm/project-42 --template python-node-browser --labels '{"scope":"project-42"}' --idle-policy never
|
|
902
|
+
shard ws list --labels '{"scope":"project-42"}' --json
|
|
903
|
+
shard ws labels qm/project-42 --set '{"scope":"project-42","owner":"qm"}'
|
|
904
|
+
shard ws idle qm/project-42 --json
|
|
905
|
+
shard ws idle qm/project-42 --keepalive 60
|
|
906
|
+
shard ws idle qm/project-42 --policy adaptive
|
|
907
|
+
shard ws suspend qm/project-42 --when-idle 2s
|
|
908
|
+
shard ws exec-start qm/project-42 --stdin-open --session-id qm-worker-1 -- cat
|
|
909
|
+
shard ws exec-input qm/project-42 qm-worker-1 hello --offset 0
|
|
910
|
+
shard ws exec-input qm/project-42 qm-worker-1 --offset 5 --close
|
|
911
|
+
```
|
|
912
|
+
|
|
913
|
+
Use the byte offset in each acknowledgement, including partial writes. `ws resume` can recover a failed workspace with its existing ID and disk. A completed delete frees the key; old IDs remain deleted. Protocol-error JSON includes `source`; HTTP 404 alone does not mean a workspace was deleted.
|
package/dist/args.d.ts
CHANGED
package/dist/args.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import { parseArgs } from 'node:util';
|
|
13
13
|
import { ACCOUNT_COMMANDS } from "./account-args.js";
|
|
14
14
|
import { UsageError } from "./errors.js";
|
|
15
|
-
export const CLI_VERSION = '0.
|
|
15
|
+
export const CLI_VERSION = '0.8.0';
|
|
16
16
|
export const GLOBAL_OPTIONS = {
|
|
17
17
|
'api-url': { type: 'string', value: '<url>', description: 'API base URL (default $SHARDFLUX_API_URL, else https://api.shardflux.dev).' },
|
|
18
18
|
json: { type: 'boolean', description: 'Print machine-readable JSON on stdout (errors as JSON on stderr).' },
|
|
@@ -27,6 +27,15 @@ const CAPS = {
|
|
|
27
27
|
'memory-mib': { type: 'string', value: '<n>', description: 'Memory cap in MiB.' },
|
|
28
28
|
'disk-gib': { type: 'string', value: '<n>', description: 'Disk cap in GiB.' },
|
|
29
29
|
};
|
|
30
|
+
/** Elastic memory (0.8.0+): the memory allocation of a workspace's caps (open and fork only). */
|
|
31
|
+
const MEMORY_ALLOCATION = {
|
|
32
|
+
'allocation-mode': {
|
|
33
|
+
type: 'string',
|
|
34
|
+
value: '<fixed|elastic>',
|
|
35
|
+
description: 'elastic: --memory-mib is a promise; the workspace holds --memory-held while idle and the host grows it when a command needs it (needs the elastic memory entitlement). Takes effect at the next VM start. Caps given without it make the workspace fixed; a command without caps keeps the stored layout.',
|
|
36
|
+
},
|
|
37
|
+
'memory-held': { type: 'string', value: '<mib>', description: 'With --allocation-mode elastic: memory held while idle, in MiB (at least 512, default 1024, at most --memory-mib).' },
|
|
38
|
+
};
|
|
30
39
|
/** `--timing` (0.3.0+): the SDK's lifecycle timing of the command's open, wait or wake (README "Timing"). */
|
|
31
40
|
const TIMING = {
|
|
32
41
|
timing: {
|
|
@@ -189,6 +198,8 @@ const KEY_COMMANDS = [
|
|
|
189
198
|
positionals: [{ name: 'key', required: true }],
|
|
190
199
|
options: {
|
|
191
200
|
template: { type: 'string', value: '<slug>', description: 'Template slug (required), e.g. python-node-browser.' },
|
|
201
|
+
labels: { type: 'string', value: '<json>', description: 'Replace workspace labels with a JSON object of strings.' },
|
|
202
|
+
'idle-policy': { type: 'string', value: '<policy>', description: 'adaptive, never or fixed:<seconds>.' },
|
|
192
203
|
secret: {
|
|
193
204
|
type: 'string',
|
|
194
205
|
multiple: true,
|
|
@@ -207,6 +218,7 @@ const KEY_COMMANDS = [
|
|
|
207
218
|
},
|
|
208
219
|
...INPUTS,
|
|
209
220
|
...CAPS,
|
|
221
|
+
...MEMORY_ALLOCATION,
|
|
210
222
|
wait: { type: 'boolean', description: 'Wait until ready (default; --no-wait returns at once). Ready includes the template’s start commands and services.' },
|
|
211
223
|
timeout: { type: 'string', value: '<duration>', description: 'Give up waiting after this long (default 5m). The start continues server side; one waiting for capacity gives up 15 minutes after it began (capacity_unavailable, retryable).' },
|
|
212
224
|
...TIMING,
|
|
@@ -219,6 +231,7 @@ const KEY_COMMANDS = [
|
|
|
219
231
|
'shard ws open acme/demo --template python-node-browser --no-wait --json',
|
|
220
232
|
'shard ws open acme/demo --template python-node-browser --timing',
|
|
221
233
|
'shard ws open acme/agent-7 --template python-node-browser --mode file-first',
|
|
234
|
+
'shard ws open acme/demo --template python-node-browser --memory-mib 8192 --allocation-mode elastic --memory-held 1024',
|
|
222
235
|
],
|
|
223
236
|
},
|
|
224
237
|
{
|
|
@@ -228,6 +241,7 @@ const KEY_COMMANDS = [
|
|
|
228
241
|
options: {
|
|
229
242
|
state: { type: 'string', value: '<state>', description: 'Observed state filter (running, suspended, creating, ...).' },
|
|
230
243
|
prefix: { type: 'string', value: '<key-prefix>', description: 'Only keys starting with this prefix.' },
|
|
244
|
+
labels: { type: 'string', value: '<json>', description: 'Exact label matches (JSON object; all pairs must match).' },
|
|
231
245
|
...LIFETIME_FILTER,
|
|
232
246
|
'include-deleted': { type: 'boolean', description: 'Include deleted workspaces and ended sessions (tombstones).' },
|
|
233
247
|
all: { type: 'boolean', description: 'Fetch every page.' },
|
|
@@ -235,6 +249,49 @@ const KEY_COMMANDS = [
|
|
|
235
249
|
cursor: { type: 'string', value: '<cursor>', description: 'Continue from a previous page.' },
|
|
236
250
|
},
|
|
237
251
|
},
|
|
252
|
+
{ path: ['workspaces', 'labels'], summary: 'Read or replace workspace labels', positionals: [REF], options: {
|
|
253
|
+
set: { type: 'string', value: '<json>', description: 'Replace all labels; {} clears them.' },
|
|
254
|
+
} },
|
|
255
|
+
{ path: ['workspaces', 'idle'], summary: 'Inspect idle status, set policy or declare a keepalive', positionals: [REF], options: {
|
|
256
|
+
policy: { type: 'string', value: '<policy>', description: 'adaptive, never, fixed:<seconds>, or default to clear the override.' },
|
|
257
|
+
keepalive: { type: 'string', value: '<seconds>', description: 'Declare ongoing work for this many seconds.' },
|
|
258
|
+
} },
|
|
259
|
+
{
|
|
260
|
+
path: ['workspaces', 'exec-start'],
|
|
261
|
+
summary: 'Start a background exec session with optional pipe stdin',
|
|
262
|
+
description: 'Runs argv directly (no shell; use `-- bash -lc "..."` for shell syntax) and returns the session at once (JSON on stdout). Read it with "shard ws exec-read", stop it with "shard ws exec-cancel".',
|
|
263
|
+
positionals: [REF, { name: 'command', required: true, variadic: true }],
|
|
264
|
+
options: {
|
|
265
|
+
'stdin-open': { type: 'boolean', description: 'Keep pipe stdin open for exec-input.' },
|
|
266
|
+
'session-id': { type: 'string', value: '<id>', description: 'Caller-chosen id to deduplicate starts.' },
|
|
267
|
+
cwd: { type: 'string', value: '<dir>', description: 'Absolute working directory.' },
|
|
268
|
+
timeout: { type: 'string', value: '<duration>', description: 'Kill the command after this long (e.g. 30m, 2h; none unless set). The workspace stays awake until the command ends or this passes (1 hour when unset).' },
|
|
269
|
+
},
|
|
270
|
+
examples: ['shard ws exec-start acme/demo --session-id build-1 --timeout 2h -- bash -lc "make -C /home/user/app"', 'shard ws exec-read acme/demo build-1 --follow'],
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
path: ['workspaces', 'exec-read'],
|
|
274
|
+
summary: 'Print a background exec session’s output and state; --follow streams it until the command exits',
|
|
275
|
+
description: 'Prints the session’s stdout and stderr from the start. When the command has ended, shard exits with its exit code (124 if it timed out, 128+N if killed by signal N); while it still runs, exit 5. --follow keeps streaming until it ends and resumes from byte offsets after dropped connections; Ctrl-C stops following, the command keeps running. --json prints one object at the end.',
|
|
276
|
+
positionals: [REF, { name: 'session-id', required: true }],
|
|
277
|
+
options: {
|
|
278
|
+
follow: { type: 'boolean', short: 'f', description: 'Stream the output until the command exits, then exit with its exit code.' },
|
|
279
|
+
},
|
|
280
|
+
examples: ['shard ws exec-read acme/demo build-1', 'shard ws exec-read acme/demo build-1 --follow', 'shard ws exec-read acme/demo build-1 --json'],
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
path: ['workspaces', 'exec-cancel'],
|
|
284
|
+
summary: 'Stop a background exec session: SIGTERM, then SIGKILL after the grace',
|
|
285
|
+
positionals: [REF, { name: 'session-id', required: true }],
|
|
286
|
+
options: {
|
|
287
|
+
grace: { type: 'string', value: '<duration>', description: 'Time between SIGTERM and SIGKILL (e.g. 10s; at most 60s; default 5s).' },
|
|
288
|
+
},
|
|
289
|
+
examples: ['shard ws exec-cancel acme/demo build-1', 'shard ws exec-cancel acme/demo build-1 --grace 30s'],
|
|
290
|
+
},
|
|
291
|
+
{ path: ['workspaces', 'exec-input'], summary: 'Write pipe stdin at its acknowledged byte offset', positionals: [REF, { name: 'session-id', required: true }, { name: 'data' }], options: {
|
|
292
|
+
offset: { type: 'string', value: '<bytes>', description: 'Required acknowledged offset (0 initially).' },
|
|
293
|
+
close: { type: 'boolean', description: 'Send EOF after these bytes are accepted.' },
|
|
294
|
+
} },
|
|
238
295
|
{ path: ['workspaces', 'get'], summary: 'Show one workspace (state, template, startup)', positionals: [REF], options: {} },
|
|
239
296
|
{ path: ['workspaces', 'inputs'], summary: 'Show the text inputs of a workspace (secret inputs are bound secrets: shard ws secrets)', positionals: [REF], options: {} },
|
|
240
297
|
{
|
|
@@ -253,10 +310,16 @@ const KEY_COMMANDS = [
|
|
|
253
310
|
description: 'File-first: the execution’s id (8-128 of A-Z a-z 0-9 . _ : -, starting with a letter or digit; default a fresh ex-<uuid>). Running the same command again with the same id returns its recorded result instead of running it twice, so scripts can repeat the call safely.',
|
|
254
311
|
},
|
|
255
312
|
'output-limit': { type: 'string', value: '<bytes>', description: 'File-first: keep at most this many bytes of stdout and of stderr each (1-16777216; default 1 MiB).' },
|
|
313
|
+
burst: {
|
|
314
|
+
type: 'boolean',
|
|
315
|
+
description: 'Processful: run this command on a larger, short-lived burst VM on the workspace’s host and apply its file changes back when it exits (needs the burst execution entitlement). Its processes and tmpfs content do not come back; the workspace’s own processes pause meanwhile. Not with --stdin; cannot be canceled.',
|
|
316
|
+
},
|
|
317
|
+
'burst-vcpus': { type: 'string', value: '<n>', description: 'With --burst: the burst VM’s vCPUs (1-32; default the host’s, 8, or the plan’s ceiling when lower).' },
|
|
318
|
+
'burst-memory': { type: 'string', value: '<mib>', description: 'With --burst: the burst VM’s memory in MiB (512-65536; default the host’s, 8192, or the plan’s ceiling when lower).' },
|
|
256
319
|
verbose: {
|
|
257
320
|
type: 'boolean',
|
|
258
321
|
short: 'v',
|
|
259
|
-
description: 'After the output, print on stderr what ran: file-first: execution id, state, base -> tree revision, replayed, timings and the changed paths (A|M|D path); processful: the session id and exit status.',
|
|
322
|
+
description: 'After the output, print on stderr what ran: file-first: execution id, state, base -> tree revision, replayed, timings and the changed paths (A|M|D path); processful: the session id and exit status (and with --burst the burst: size, method, applied changes, overhead).',
|
|
260
323
|
},
|
|
261
324
|
...WAKE_TIMING,
|
|
262
325
|
},
|
|
@@ -265,26 +328,28 @@ const KEY_COMMANDS = [
|
|
|
265
328
|
'shard ws exec acme/demo --cwd /home/user/app --env CI=1 -- bash -lc "npm test"',
|
|
266
329
|
'shard ws exec acme/agent-7 -v --execution-id build-42 --timeout 10m -- bash -lc "make -C /home/user/app"',
|
|
267
330
|
'shard ws exec acme/agent-7 --json -- python3 /home/user/report.py > result.json',
|
|
331
|
+
'shard ws exec acme/demo --burst --burst-vcpus 16 -v -- bash -lc "cd /home/user/app && go build ./..."',
|
|
268
332
|
],
|
|
269
333
|
},
|
|
270
334
|
{
|
|
271
335
|
path: ['workspaces', 'suspend'],
|
|
272
|
-
summary: 'Suspend a running workspace (
|
|
273
|
-
description: 'Without options the suspend is requested now. --when-idle (0.5.1+) defers it instead: the workspace is suspended once it has been idle for that long, counted from the later of its last work and the request, so call it when an agent turn ends. A command still running, an attached exec or terminal stream, or a keepalive postpones it; the next tool call (the next turn) or a resume cancels it. Repeating replaces the pending request. --cancel-when-idle cancels it.',
|
|
336
|
+
summary: 'Suspend a running workspace (memory and processes checkpointed), now or once it has been idle',
|
|
337
|
+
description: 'Without options the suspend is requested now. With --wait it returns as soon as the workspace is sealed on its host, typically in a few hundred ms; the result\'s durable turns true when the copy lands in durable storage, typically within a second. --durable (0.7.0+) waits for that too. --when-idle (0.5.1+) defers it instead: the workspace is suspended once it has been idle for that long, counted from the later of its last work and the request, so call it when an agent turn ends. A command still running, an attached exec or terminal stream, or a keepalive postpones it; the next tool call (the next turn) or a resume cancels it. Repeating replaces the pending request. --cancel-when-idle cancels it.',
|
|
274
338
|
positionals: [REF],
|
|
275
339
|
options: {
|
|
276
340
|
'when-idle': { type: 'string', value: '<duration>', description: 'Suspend once the workspace has been idle this long (0.5.1+; 0 to 1h, e.g. 0, 30s, 2m; 0 = as soon as it is idle, 0.6.1+). Cannot be combined with --wait.' },
|
|
277
341
|
'cancel-when-idle': { type: 'boolean', description: 'Cancel a pending --when-idle request (0.5.1+; idempotent).' },
|
|
342
|
+
durable: { type: 'boolean', description: 'Wait until the suspend is in durable storage (result durable: true; 0.7.0+). Implies --wait and shares its --timeout.' },
|
|
278
343
|
...WAIT,
|
|
279
344
|
},
|
|
280
|
-
examples: ['shard ws suspend acme/demo --wait', 'shard ws suspend acme/demo --when-idle 2m', 'shard ws suspend acme/demo --cancel-when-idle'],
|
|
345
|
+
examples: ['shard ws suspend acme/demo --wait', 'shard ws suspend acme/demo --durable', 'shard ws suspend acme/demo --when-idle 2m', 'shard ws suspend acme/demo --cancel-when-idle'],
|
|
281
346
|
},
|
|
282
347
|
{ path: ['workspaces', 'resume'], summary: 'Resume a suspended workspace', positionals: [REF], options: { ...WAIT } },
|
|
283
348
|
{
|
|
284
349
|
path: ['workspaces', 'fork'],
|
|
285
350
|
summary: 'Fork a workspace into a new key',
|
|
286
351
|
positionals: [REF, { name: 'new-key', required: true }],
|
|
287
|
-
options: { ...CAPS, ...WAIT },
|
|
352
|
+
options: { ...CAPS, ...MEMORY_ALLOCATION, ...WAIT },
|
|
288
353
|
},
|
|
289
354
|
{
|
|
290
355
|
path: ['workspaces', 'delete'],
|
|
@@ -695,7 +760,11 @@ const KEY_COMMANDS = [
|
|
|
695
760
|
path: ['operations', 'wait'],
|
|
696
761
|
summary: 'Wait for an operation to finish (exit 0 succeeded, 6 failed/canceled, 5 timeout)',
|
|
697
762
|
positionals: [{ name: 'operation-id', required: true }],
|
|
698
|
-
options: {
|
|
763
|
+
options: {
|
|
764
|
+
timeout: { type: 'string', value: '<duration>', description: 'Give up after this long (default 5m).' },
|
|
765
|
+
durable: { type: 'boolean', description: 'A suspend or fork: also wait until its copy is in durable storage (result durable: true; 0.7.0+).' },
|
|
766
|
+
...TIMING,
|
|
767
|
+
},
|
|
699
768
|
},
|
|
700
769
|
];
|
|
701
770
|
/** Every command: the account plane first (sign in, set up), then the project-key commands. */
|