@shardflux/cli 0.4.1 → 0.5.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/CHANGELOG.md CHANGED
@@ -3,6 +3,232 @@
3
3
  Every command and option the README shows is available from the version named here. Below 1.0, a minor release may
4
4
  break compatibility; breaking changes are marked **Breaking**.
5
5
 
6
+ ## 0.5.1 (not yet published; npm `latest` is 0.5.0)
7
+
8
+ ### A command that could not start is never a silent exit
9
+
10
+ Production (2026-09-29): `shard ws exec <key> --cwd app -- ls` exited 1 and printed nothing on stdout or stderr. The
11
+ cell had ended the session `failed_to_start` (`working directory "app" is not a directory`).
12
+
13
+ - `shard ws exec` on a processful workspace: a command that could not start (a `--cwd` that is not a directory, a
14
+ program not on `PATH`, an unknown user) exits 6, as a failed file-first execution does, with the workspace's reason
15
+ and a hint on stderr: `error: The command could not start: working directory "/home/user/app" is not a directory
16
+ (exec_failed_to_start) [code=conflict source=cell]`, then `hint: --cwd must name a directory that exists in the
17
+ workspace, ...` (or the `PATH` hint). It exited 1 with no output. With `--json` the error document has
18
+ `details.reason` `exec_failed_to_start`, `details.error` and `details.session_id`. Through `@shardflux/sdk` 0.10.0
19
+ (`ExecStartError`).
20
+ - A relative `--cwd` is refused by the API before anything runs: 422 `invalid_cwd`, exit 2, and the message names the
21
+ absolute path it likely means (`use "/home/user/app"`). That holds for every CLI version once the cell refuses it.
22
+ - A session that ended without an exit code, timeout or signal (`lost`, when its host restarted) prints `exec session
23
+ <id> ended lost without an exit code: <reason>` on stderr; the exit code stays 1. `--json` adds `state` (and `error`
24
+ when the session has one) to the result.
25
+ - The file-first hint for `exec_failed_to_start` names `--cwd` when the reason is a working directory, instead of
26
+ always asking whether argv[0] is on `PATH`. `--cwd` help: an absolute path, default `/home/user`.
27
+
28
+ - A 402 `allowance_exhausted` and a spend-policy `version_mismatch` end without the `feedback:` line: they are billing
29
+ states whose hint names the next step, not problems to report.
30
+ ### Opt-in overage with a spend cap
31
+
32
+ - `shard usage` prints an overage block from the summary's `spend_cap`: the state (`off`, `paused`, `accruing`,
33
+ `warning`, `reached`, ...), the spend cap, the charges of the cap with what is left, the date the cap is projected
34
+ to be reached, and a table of the units past each allowance (CPU-hours, RAM GiB-hours) with the billed units, rate
35
+ and amount. Allowances past `included` while overage is on show cap state `overage`; `allowance exhausted` names the
36
+ reason (`allowance_used`, `overage_paused`, `spend_cap_reached`). An API without overage prints no block.
37
+ - `shard billing overage` (signed in; owners and billing members change it): `status` (the default: the state, the
38
+ spend cap and its range up to the plan price, the rates), `on [--cap <dollars>]`, `cap <dollars>` (e.g. `9` or
39
+ `9.50`) and `off`, with `--if-version <n>` and `--json` (the API's spend policy). A refusal exits 2 with a hint that
40
+ names the bound (`spend_cap_above_plan_price`: the plan price; `spend_cap_below_minimum`; `spend_cap_below_charges`:
41
+ what overage already charged) or the next step (`overage_unavailable`, `spend_cap_required`); a 409
42
+ `version_mismatch` (also from `egress set --if-version`) exits 1 and names the current version.
43
+ - 402 `allowance_exhausted` gets a hint per `details.reason`: `allowance_used` (upgrade, or `shard billing overage on
44
+ --cap <dollars>`), `spend_cap_reached` (raise the cap with `shard billing overage cap <dollars>`, or upgrade),
45
+ `overage_paused` (a payment is past due: update the payment method, `shard billing portal --open`). The exit code
46
+ stays 1.
47
+
48
+ ### Suspend when idle (contracts §20.6)
49
+
50
+ - `shard workspaces suspend <id|key> --when-idle <duration>` (30s to 1h): the workspace is suspended once it has been
51
+ idle that long, counted from the later of its last work and the request (suspend when idle, for the end of an agent
52
+ turn). A running command, an attached stream or a keepalive postpones it; the next tool call or a resume cancels it.
53
+ `--cancel-when-idle` cancels it. `--json` prints `{workspace, operation, suspend_request}`.
54
+ - `shard workspaces get` shows a pending request (`suspend when idle after N s idle, not before ...`).
55
+
56
+ ## 0.5.0 (not yet published; npm `latest` is 0.4.1)
57
+
58
+ Needs `@shardflux/sdk` 0.9.0 or later.
59
+
60
+ ### File search, patches and revisions (contracts §26)
61
+
62
+ - `shard files search <id|key> <path> <pattern>`: content search under a directory (or in one file), printed
63
+ grep-style (`path:line:column: text`, context lines as `path-line- text`). `--regex` (RE2), `-i`/`--ignore-case`,
64
+ repeatable gitignore-style `--include`/`--exclude` globs (`--exclude` replaces the default `.git`/`node_modules`
65
+ exclusions), `--max N` (1-5000, default 200). A search stopped early says why on stderr (`--max` matches, the 10 s
66
+ budget or 4 MiB of results); a suspended workspace searched on its disk is noted. `--json` prints
67
+ `{matches, truncated, stop_reason?, files_scanned, served_from}`.
68
+ - `shard files patch <id|key> <path>`: repeatable `--old T --new T` pairs (each must occur exactly once unless
69
+ `--replace-all`; applied in order, all or nothing) or `--content-file F|-` (UTF-8, up to 7 MiB), with
70
+ `--expected-revision <sha256|absent>`. Atomic and durable; prints the new revision (`--json`: the patch result).
71
+ - `shard files stat <id|key> <path> [--revision]`: one path's metadata; `--revision` adds the content's SHA-256, the
72
+ value `--expected-revision` takes.
73
+ - Hints for the new refusals: `revision_mismatch` (exit 1) names the current revision; `edit_not_found` and
74
+ `edit_ambiguous` (exit 2, like any `validation_failed`) name the `--old` by position; `host_capacity` says to retry
75
+ shortly (reads, searches and patches already retry it after `Retry-After`).
76
+ - A workspace on a host that predates search and patches (contracts §26.7, while the fleet is upgraded): `files
77
+ search` and `files patch` fail at once with 409 `conflict` `host_feature_unavailable` (exit 1, not retried, no
78
+ wake), with a hint naming `details.feature` and another way to do it now (`shard ws exec <id|key> -- grep -rn ...`
79
+ for a search; `files read` then `files write` for a patch); they work once the workspace runs on an upgraded host.
80
+ Such a host returns no revisions (`files stat --revision` prints none).
81
+ - All three take `--timing`. `files patch` wakes a suspended workspace like `files write`; `files search` and
82
+ `files stat` read its disk (below).
83
+ - `files read|ls|stat|search` of a suspended workspace are answered from its disk without resuming it (the state at
84
+ suspension), also on the first command after the suspend: every `shard` run fetches a new tool token, which the API
85
+ refused for a suspended workspace, so these commands used to resume it. Needs `@shardflux/sdk` 0.9.0 and an API
86
+ that issues tool tokens for suspended workspaces (contracts §26.4); with an older API they resume it as before.
87
+ Every other command still resumes it.
88
+
89
+ ### File-first workspaces (contracts §29)
90
+
91
+ - `shard workspaces open --mode processful|file-first` (`file_first` too): a file-first workspace is a versioned file
92
+ tree with no VM between commands. It is ready at once, never suspended and always persistent. Without `--mode` a new
93
+ key is processful and an existing key keeps its mode. `--mode file-first` with `--lifetime session` is a usage error.
94
+ - `shard workspaces exec` on a file-first workspace runs the command as an execution: a fresh VM on the latest tree
95
+ revision; the files it changed under /home/user become the next revision. Its stdout and stderr are printed byte for
96
+ byte when it ended, and `shard` exits with its exit code (124 timed out, 128+N killed by signal N). An execution that
97
+ ended `failed` or `lost` published nothing: exit 6, with its reason and `retryable`
98
+ (`{"error": {"code": "execution_failed", ...}}` with `--json`).
99
+ - `-v` / `--verbose`: after the output, on stderr, the execution id, state and exit status, `base -> new` tree
100
+ revision, `replayed`, the timings and the changed paths (`A|M|D path`). On a processful workspace `-v` prints the
101
+ session id and exit status.
102
+ - `--json`: one object, the cell's result with stdout/stderr as text, plus `stdout_base64` / `stderr_base64` when a
103
+ stream is not UTF-8.
104
+ - `--execution-id <id>`: the execution's idempotency key (default a fresh `ex-<uuid>`): the same id with the same
105
+ command returns the recorded result instead of running it twice. `--output-limit <bytes>` (1-16777216, default
106
+ 1 MiB per stream). Both are usage errors on a processful workspace.
107
+ - Ctrl-C stops waiting (exit 130; an execution cannot be canceled) and prints the `shard executions get` command
108
+ that fetches its result later.
109
+ - `shard executions get <id|key> <execution-id> [--wait D]` (also `shard workspaces executions get`; alias
110
+ `execution`): an execution's result, printed like `exec -v`. Exit: the command's code, 6 failed or lost, 5 while it
111
+ still runs (`--wait` waits up to D for it to end).
112
+ - `--if-revision <n>` on `shard files write` and `shard files patch`: the change applies only while the tree is at
113
+ revision n (`If-Match`). On a file-first workspace both print the tree revision after the change (`tree_revision`
114
+ with `--json`). A usage error on a processful workspace.
115
+ - `shard workspaces get` shows the mode and a file-first workspace's tree revision; `shard workspaces list` shows
116
+ `running (file-first)`.
117
+ - `shard workspaces suspend|resume|fork|reset|save-as-template` on a file-first workspace are refused without a
118
+ request (`not_supported_for_mode`, exit 1).
119
+ - Hints for the new refusals: `not_supported_for_mode` (either mode), `mode_mismatch`, `mode_not_available`,
120
+ `layout_unsupported` (file-first), `tree_revision_mismatch` (names the current revision to retry with),
121
+ `outside_tree_root`, `execution_in_progress` (names the running execution), `execution_id_reused`,
122
+ `no_execution_host`, and failed or lost executions (`exec_failed_to_start`, `lease_expired`, `host_unreachable`,
123
+ `host_restarted`, `tree_moved`, ...).
124
+ - The error line names `execution_id=` when the error is about an execution.
125
+
126
+ ### Waking a suspended workspace is one request (contracts §22.6)
127
+
128
+ - Through `@shardflux/sdk` 0.9.0: a command on a suspended workspace (`ws exec`, `files ...`, `ws changes`) wakes it
129
+ with one held resume that returns the running workspace and the CLI's tool token, then runs (refused call, resume,
130
+ the command; before: also a wait, a view and a token request). An API without the held resume works as before.
131
+ - `--timing` shows the wake as one `request` phase `(held)`; a wake that runs out of time shows the hold, then the
132
+ states it saw after it (`request 1.00 s (held) → queued …`).
133
+ - `shard workspaces resume --wait` is one held request; its tool token is attributed to the CLI's agent label.
134
+ ### The account plane (contracts §30)
135
+
136
+ Needs `@shardflux/sdk` 0.9.0 or later (`ShardfluxAccount`, `checkClientVersion`) and an API with CLI sessions
137
+ (contracts §30).
138
+
139
+ ### Everything the web app does, from a terminal (docs/progress/account-cli.md §5)
140
+
141
+ - **Accounts and sign-in:** `shard auth register|verify-email|resend-verification|login|mfa|status|logout|sessions|step-up`,
142
+ `shard auth password change|reset|reset-confirm`, `shard auth email change|confirm`,
143
+ `shard auth totp enroll|confirm|disable|recovery-codes`. A sign-in is a CLI session (`sfu_...`, 30 days of use,
144
+ at most 90) on the SDK's `ShardfluxAccount`. Emailed links (or their tokens) are arguments; passwords never are:
145
+ they come from standard input (one line per secret) or a no-echo prompt on a terminal (a new password twice).
146
+ Two-factor sign-in takes `--code`/`--recovery-code` or the prompt; without either the pending sign-in is saved
147
+ and `shard auth mfa --code` completes it (`auth login` exits 4, `mfa_required`). After signing in `shard` prints
148
+ the user, whether the email is verified, the organizations and the next step.
149
+ - **`shard setup`:** uses (or creates) the organization ("<name>'s organization") and project ("Default"), creates
150
+ an API key with every tool (or `--tool`), saves it and checks it against the API. Idempotent: a working saved key
151
+ is kept (`--new-key` for another). `shard env [--shell sh|fish|powershell]` prints the saved key as exports.
152
+ - **Organizations, projects, keys, members:** `shard orgs list|create|get|use|workspaces|export|deletion|delete` (`workspaces`: every project's workspaces, as the dashboard lists them),
153
+ `shard projects list|create|get|use`, `shard api-keys list|create|revoke` (the new key is printed once, alone
154
+ on stdout, or saved with `--save`), `shard members list|set-role|remove`,
155
+ `shard invitations list|create|revoke|accept`, `shard templates publish|archive <slug>@<version>`. Default
156
+ organization and project: `--org`/`--project` (id or slug), else the saved default (`orgs use`, `projects use`,
157
+ `setup`), else the only one; with several the usage error lists them.
158
+ - **Billing:** `shard billing plans` (public, no sign-in), `status`, `upgrade <plan> [--open] [--wait] [--timeout]`
159
+ (Stripe Checkout URL; `--wait` exits 0 once the webhook activated the subscription, 6 when the checkout expired or
160
+ was canceled, 5 on `--timeout`, default 15m; an organization with a subscription gets the portal URL instead),
161
+ `portal [--open]`, `invoices`, `alerts [--set 50,80,100 | --clear]`.
162
+ - **Usage:** `shard usage --estimate` (the bill so far, projected allowance use), `--series` (usage over time;
163
+ `--from`, `--to`, `--granularity hour|day`, `--meter`) and `--workspace <id|key>` (one workspace's usage), as the
164
+ dashboard's usage page shows; `shard usage` alone is the summary as before.
165
+ - **Audit, exports, deletion:** `shard audit list|export`, `shard account status|export|delete|cancel-deletion`.
166
+ Exports are downloaded to 0600 files (`./<kind>-export-<id>.json` by default) and never overwrite without `--force`.
167
+ - **Egress and volumes** with the project key: `shard egress get|set|history|clear`,
168
+ `shard volumes list|create|get|delete|attachments|attach|detach`.
169
+ - **Step-up:** a command that answers 403 `step_up_required` asks for the password (and a code with two-factor
170
+ authentication) on a terminal and retries once; without a terminal it exits 4 with the hint
171
+ `printf '%s\n' "$PASSWORD" | shard auth step-up`.
172
+ - Destructive commands need `--yes`, and the typed `--confirm` value where the API asks for one (organization slug,
173
+ your email).
174
+ - New exit-code cases: 4 for `step_up_required`, `mfa_required`, `email_unverified`, `invalid_credentials`,
175
+ `token_invalid`; 5 and 6 for `billing upgrade --wait` (`timeout`, `checkout_ended`).
176
+
177
+ ### The credentials file (**behaviour change**)
178
+
179
+ Before 0.5.0 `shard` stored nothing. It now keeps `credentials.json` in its config directory
180
+ (`$SHARDFLUX_CONFIG_DIR`, else `$XDG_CONFIG_HOME/shardflux`, else `~/.config/shardflux`, `%APPDATA%\shardflux` on
181
+ Windows): directory 0700, file 0600, atomic writes, one profile per API URL with the session, the default
182
+ organization and project, and the saved API key. It is written only by `auth login`/`auth mfa`, `setup`,
183
+ `api-keys create --save`, `orgs use`/`projects use`/`invitations accept --use` and session renewals. Environment
184
+ variables still win: `SHARDFLUX_API_KEY` over the saved key, the new `SHARDFLUX_SESSION_TOKEN` over the saved
185
+ session. A corrupt file is a usage error naming it and is moved aside (never overwritten) before a new one is
186
+ written. A saved session the API rejects is removed with a hint to sign in again. `shard login` (the key check) is
187
+ unchanged and still stores nothing.
188
+
189
+ ### Version check
190
+
191
+ - `shard` checks `GET /v1/client-versions` at most once a day per API URL (cached in
192
+ `<config dir>/update-check.json`), in parallel with the command, and prints one line on stderr when it is outdated
193
+ or no longer supported. A late answer is skipped (at most ~300 ms of waiting), the exit code never changes, and
194
+ nothing is printed after a `--json` failure. Off with `SHARDFLUX_NO_UPDATE_CHECK=1` or `NO_UPDATE_NOTIFIER=1`. The
195
+ SDK's own check is off inside `shard` (`versionCheck: false`).
196
+ - `shard version` shows the update status; `shard version --check` asks now; `--json` adds
197
+ `update: {package, current, status, latest, minimum_supported, upgrade_command, checked_at}`.
198
+ - `main({ distribution: { package, version } })` (exported): the `shardflux` npm bundle runs the CLI under its own
199
+ name, so its users are told to update `shardflux`.
200
+
201
+ ### Also
202
+
203
+ - `redact()` removes user session tokens (`sfu_...`) from error output, as it does API keys.
204
+ - `--password`, `--token`, `--key`, `--secret`, `--api-key` stay refused; the messages name the new sources.
205
+ - The top help starts with the no-browser path and groups commands by the credential they use; `shard <group>`
206
+ and `shard auth totp` (a sub-group) list their commands.
207
+
208
+ ### Feedback straight to the founder (needs an API with POST /v1/feedback)
209
+
210
+ - `shard feedback [--category bug|confusing|missing|idea|praise|other] [--workspace W] [--request-id ID]
211
+ [--error-code CODE] [--command TEXT] [--from-file F|-] <message...>` sends feedback to the Shardflux founder by
212
+ email. The message is the remaining words (no quotes needed unless the shell needs them) or `--from-file` (`-`:
213
+ standard input, for logs). It is checked before any request (1-8000 characters, a known category, the context
214
+ bounds). The context carries `client: shard-cli/0.5.0` and, unless it is the default `cli`, the agent label as
215
+ `agent`. Output: one line with the feedback id, or `Already received` for a duplicate within 24 hours; `--json`:
216
+ `{id, received_at, duplicate}`. It sends with the project API key, or, when none is configured, with the signed-in
217
+ session (`SHARDFLUX_SESSION_TOKEN` or the saved one). Without either, or when rate limited, the hint says how to
218
+ continue or to email shardflux@heliosone.fi.
219
+ - `shard --help` opens with a Feedback section, and `shard feedback --help` explains when to use each category: coding
220
+ agents are asked to send short feedback while they work, the moment something fails, confuses or is missing, and to
221
+ pass on (paraphrased, without private data) what their user is frustrated about or asked for that Shardflux could not
222
+ do, telling the user they sent it.
223
+ - A failure ends with
224
+ `feedback: shard feedback --category bug --request-id <id> --error-code <code> "<what you expected>"`; with `--json`
225
+ the error object gains a sibling `"feedback"` field holding that command. Existing fields are unchanged. Not for
226
+ the expected flow: usage and validation errors, Ctrl-C, a missing or refused credential, a sign-in or step-up to
227
+ finish, a wait that gave up, a checkout nobody paid, refusals whose hint names the next step (a stale revision, an
228
+ edit that does not match, a mode the workspace lacks, a reused execution id), and `shard feedback` itself.
229
+ - The positional usage of `shard feedback` is shown as `<message...>`; `--agent-label` also names the reporting agent.
230
+
231
+
6
232
  ## 0.4.1 (2026-09-28)
7
233
 
8
234
  Needs `@shardflux/sdk` 0.8.0 or later. No command changes: the SDK's 0.8.0 is a types-only release (its provider tool