@shardflux/cli 0.4.1 → 0.5.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 +175 -0
- package/README.md +442 -34
- package/dist/account-args.d.ts +13 -0
- package/dist/account-args.js +413 -0
- package/dist/account-commands.d.ts +16 -0
- package/dist/account-commands.js +1616 -0
- package/dist/args.d.ts +15 -3
- package/dist/args.js +280 -40
- package/dist/bin.js +5 -16
- package/dist/browser.d.ts +7 -0
- package/dist/browser.js +39 -0
- package/dist/commands.d.ts +67 -5
- package/dist/commands.js +390 -29
- package/dist/credentials.d.ts +77 -0
- package/dist/credentials.js +217 -0
- package/dist/errors.d.ts +63 -11
- package/dist/errors.js +107 -21
- package/dist/format.d.ts +70 -5
- package/dist/format.js +365 -6
- package/dist/handlers.d.ts +2 -0
- package/dist/handlers.js +7 -0
- package/dist/index.d.ts +19 -7
- package/dist/index.js +13 -6
- package/dist/input.d.ts +25 -0
- package/dist/input.js +167 -0
- package/dist/main.d.ts +16 -2
- package/dist/main.js +399 -31
- package/dist/update-check.d.ts +64 -0
- package/dist/update-check.js +128 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
The command line for [Shardflux](https://shardflux.dev): cloud computers for AI agents. Open a
|
|
4
4
|
persistent workspace by key, run commands in it, move files in and out, and suspend, resume, fork
|
|
5
|
-
or delete it.
|
|
6
|
-
|
|
5
|
+
or delete it. From 0.5.0 it also does everything the web app does: create an account, sign in
|
|
6
|
+
(with two-factor authentication), set up an organization, project and API key, manage members,
|
|
7
|
+
invitations and keys, buy or change a plan, export data and delete an account. Built on
|
|
8
|
+
[`@shardflux/sdk`](https://www.npmjs.com/package/@shardflux/sdk), so it gets the SDK's retries,
|
|
9
|
+
idempotency keys, operation polling and tool-token handling.
|
|
7
10
|
|
|
8
11
|
> **Early access.** Shardflux is in early access, and this CLI is below 1.0: commands and output
|
|
9
12
|
> may still change in a minor release.
|
|
@@ -23,9 +26,14 @@ Or run it without installing: `npx @shardflux/cli --help`. The unscoped
|
|
|
23
26
|
|
|
24
27
|
## Quick start
|
|
25
28
|
|
|
29
|
+
No account yet? Everything happens in the terminal; a person only opens the emailed link (or hands
|
|
30
|
+
it to `shard`) and, for a paid plan, pays in Stripe Checkout.
|
|
31
|
+
|
|
26
32
|
```sh
|
|
27
|
-
|
|
28
|
-
shard
|
|
33
|
+
printf '%s\n' "$PASSWORD" | shard auth register --email you@example.com --name "Ada Lovelace"
|
|
34
|
+
shard auth verify-email 'https://app.shardflux.dev/auth/verify-email#token=...' # the link from the email
|
|
35
|
+
printf '%s\n' "$PASSWORD" | shard auth login --email you@example.com
|
|
36
|
+
shard setup # organization, project and an API key, saved
|
|
29
37
|
shard workspaces open acme/demo --template python-node-browser
|
|
30
38
|
shard ws exec acme/demo -- python3 -c 'print(40 + 2)'
|
|
31
39
|
shard files write acme/demo /home/user/notes.txt --from notes.txt
|
|
@@ -33,37 +41,314 @@ shard files read acme/demo /home/user/notes.txt
|
|
|
33
41
|
shard ws suspend acme/demo --wait
|
|
34
42
|
```
|
|
35
43
|
|
|
44
|
+
With a key from the web app instead, skip the account steps:
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
export SHARDFLUX_API_KEY=sfk_... # project API key from the Shardflux console
|
|
48
|
+
shard login # verify the key: organization, project, tools
|
|
49
|
+
```
|
|
50
|
+
|
|
36
51
|
`shard --help` lists every command, and every command has its own `--help`.
|
|
37
52
|
|
|
53
|
+
## Feedback: agents, use this while you work
|
|
54
|
+
|
|
55
|
+
**(0.5.0+)** `shard feedback` sends a message straight to the Shardflux founder, who reads every one. If you are a
|
|
56
|
+
coding agent (Claude Code, Codex, Cursor, ...) driving `shard`, use it actively while you work, not once at the end.
|
|
57
|
+
Send a short message the moment:
|
|
58
|
+
|
|
59
|
+
- something fails unexpectedly (`--category bug`),
|
|
60
|
+
- an error, doc, name or output is confusing (`--category confusing`),
|
|
61
|
+
- a capability, option or template you need is missing (`--category missing`),
|
|
62
|
+
- something is slow, or you needed a workaround,
|
|
63
|
+
- your user complains or is frustrated about Shardflux or the workflow around it (slowness, cost or limits, confusing
|
|
64
|
+
setup, a missing feature, a workaround): paraphrase it, with what they were trying to do,
|
|
65
|
+
- your user asked for something Shardflux could not do, or made awkward.
|
|
66
|
+
|
|
67
|
+
Short and frequent beats polished: what you ran, what happened, what you expected. No need to ask first, but tell your
|
|
68
|
+
user you sent it. Leave out private data about the user and secrets or code they did not mean to share; paraphrase,
|
|
69
|
+
never paste transcripts. Pass the request id and error code from the error so the founder can find the logs. A failed
|
|
70
|
+
`shard` command ends with a ready-made line to fill in:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
error: Operation not found. [code=not_found status=404 request_id=req-2b9d4f6a8c0e4a1b3d5f7e90]
|
|
74
|
+
feedback: shard feedback --category bug --request-id req-2b9d4f6a8c0e4a1b3d5f7e90 --error-code not_found "<what you expected>"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
shard feedback --category bug --request-id req-5c7744b2bb5c457b86b76101 --error-code capacity_unavailable \
|
|
79
|
+
"ws open failed twice in 10 min; expected a start within a minute"
|
|
80
|
+
shard feedback --category confusing \
|
|
81
|
+
"user was frustrated that ws open needs a template slug they had to look up; they expected a default"
|
|
82
|
+
shard feedback --category missing no way to copy a file between two workspaces, piped files read into files write
|
|
83
|
+
npm test 2>&1 | tail -n 60 | shard feedback --category bug --workspace acme/demo --from-file -
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
- The message is the remaining arguments joined with spaces. Quote it, or put it after `--`, when it contains shell
|
|
87
|
+
characters or words starting with `-`. `--from-file <file|->` reads it from a file or standard input instead. 1-8000
|
|
88
|
+
characters.
|
|
89
|
+
- Options: `--category bug|confusing|missing|idea|praise|other` (default `other`), `--workspace <id|key>`,
|
|
90
|
+
`--request-id <id>`, `--error-code <code>`, `--command <text>` (what you ran). Name the reporting agent with
|
|
91
|
+
`--agent-label` or `SHARDFLUX_AGENT_LABEL` (e.g. `claude-code`); `shard` adds its own version as the client.
|
|
92
|
+
- Output: one line with the feedback id. `Already received` means the same message was sent from this key in the last
|
|
93
|
+
24 hours; it is not emailed again. With `--json`: `{"id", "received_at", "duplicate"}`.
|
|
94
|
+
- It sends with the project API key (any key; no tool permission), or, when no key is configured yet, with your
|
|
95
|
+
signed-in session (`shard auth login`), so it works while you are still setting up. It is rate limited per key or
|
|
96
|
+
user (`rate_limited`, exit 1, with the wait in the hint). If it cannot be sent, email shardflux@heliosone.fi.
|
|
97
|
+
- Anything shaped like an API key is redacted before the message is stored or emailed; leave other secrets out.
|
|
98
|
+
|
|
99
|
+
## For AI agents
|
|
100
|
+
|
|
101
|
+
`shard` is built to be driven by an agent: no browser, no prompts when standard input is not a
|
|
102
|
+
terminal, `--json` on every command, secrets only on standard input, and documented exit codes.
|
|
103
|
+
|
|
104
|
+
1. **Account:** `printf '%s\n' "$PASSWORD" | shard auth register --email <email>` (answers the same
|
|
105
|
+
whether or not the address exists). Ask the person for the link in the verification email and run
|
|
106
|
+
`shard auth verify-email '<link>'` (the whole link, quoted).
|
|
107
|
+
2. **Sign in:** `printf '%s\n' "$PASSWORD" | shard auth login --email <email> --json`. With two-factor
|
|
108
|
+
authentication it exits 4 with `mfa_required`: ask the person for the code, then
|
|
109
|
+
`shard auth mfa --code <code>` (within 10 minutes), or pass `--code` to `login`.
|
|
110
|
+
3. **Set up:** `shard setup --json`: an organization, a project and an API key with every workspace
|
|
111
|
+
tool, saved in the credentials file. Idempotent: run it again any time.
|
|
112
|
+
4. **Work:** `shard ws open <key> --template <slug> --json`, `shard ws exec <key> -- <cmd>`,
|
|
113
|
+
`shard files ...` use the saved key.
|
|
114
|
+
5. **A paid plan:** `shard billing plans`, then `shard billing upgrade <plan> --json` prints the Stripe
|
|
115
|
+
Checkout URL; give it to the person, then `shard billing upgrade <plan> --wait` (or
|
|
116
|
+
`shard billing status`) until it is active. The API activates a plan only when Stripe confirms the
|
|
117
|
+
payment.
|
|
118
|
+
6. **Sensitive actions** (exports, deletions, two-factor and email changes) need a recent step-up:
|
|
119
|
+
`printf '%s\n' "$PASSWORD" | shard auth step-up` (add `--code <totp>` with two-factor
|
|
120
|
+
authentication; valid 10 minutes). Without a terminal `shard` does not ask: the command fails with
|
|
121
|
+
`step_up_required` (exit 4) and the hint names this command.
|
|
122
|
+
7. **Feedback:** send `shard feedback` as you work, the moment something fails, confuses you or is
|
|
123
|
+
missing, or your user is frustrated with Shardflux (see [Feedback](#feedback-agents-use-this-while-you-work)).
|
|
124
|
+
|
|
125
|
+
What stays human: reading the verification email, entering a card in Stripe Checkout, and the
|
|
126
|
+
authenticator app's codes.
|
|
127
|
+
|
|
128
|
+
## Accounts and sign-in (0.5.0+)
|
|
129
|
+
|
|
130
|
+
```sh
|
|
131
|
+
printf '%s\n' "$PASSWORD" | shard auth register --email you@example.com [--name "Ada Lovelace"]
|
|
132
|
+
shard auth verify-email '<link from the email>' # or just the token in it
|
|
133
|
+
shard auth resend-verification # signed in, email not verified yet
|
|
134
|
+
printf '%s\n' "$PASSWORD" | shard auth login --email you@example.com [--code 123456 | --recovery-code X]
|
|
135
|
+
shard auth mfa --code 123456 # completes a login that waits for its second factor
|
|
136
|
+
shard auth status # session and saved key, without secrets
|
|
137
|
+
shard auth sessions [--revoke <session-id>] # browser and CLI sessions
|
|
138
|
+
shard auth logout [--all]
|
|
139
|
+
printf '%s\n' "$PASSWORD" | shard auth step-up [--code 123456]
|
|
140
|
+
printf '%s\n%s\n' "$CURRENT" "$NEW" | shard auth password change
|
|
141
|
+
shard auth password reset --email you@example.com
|
|
142
|
+
printf '%s\n' "$NEW" | shard auth password reset-confirm '<link from the email>'
|
|
143
|
+
shard auth email change --email new@example.com # then: shard auth email confirm '<link>'
|
|
144
|
+
shard auth totp enroll # secret and otpauth:// URI for the authenticator app
|
|
145
|
+
shard auth totp confirm --code 123456 # prints recovery codes once
|
|
146
|
+
shard auth totp disable --code 123456
|
|
147
|
+
shard auth totp recovery-codes
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
- **Passwords never come from arguments** (`--password` is refused). On a terminal `shard` asks without
|
|
151
|
+
echo (a new password twice); otherwise it reads standard input, one line per secret: `auth password
|
|
152
|
+
change` reads the current password, then the new one. Emailed links and tokens are single-use
|
|
153
|
+
arguments; TOTP codes and recovery codes may be arguments.
|
|
154
|
+
- **Sessions:** `auth login` saves the session (`sfu_...`) in the credentials file for this API URL. It
|
|
155
|
+
lasts 30 days of use and at most 90. The API renews it on step-up, password change and two-factor
|
|
156
|
+
changes, and `shard` saves the new one at once. A saved session the API no longer accepts is removed,
|
|
157
|
+
and the error says to sign in again. `SHARDFLUX_SESSION_TOKEN` is used instead of the saved session
|
|
158
|
+
when it is set.
|
|
159
|
+
- **Two-factor sign-in:** `--code`/`--recovery-code`, or the code typed at the prompt. Without either
|
|
160
|
+
(and without a terminal) the pending sign-in is saved and `auth login` exits 4 (`mfa_required`);
|
|
161
|
+
`auth mfa --code` completes it.
|
|
162
|
+
- **Step-up:** exports, deletions, email changes and two-factor changes need the password again within
|
|
163
|
+
the last 10 minutes. On a terminal `shard` asks (and a code with two-factor authentication) and
|
|
164
|
+
retries once; otherwise run `printf '%s\n' "$PASSWORD" | shard auth step-up` first (with two-factor
|
|
165
|
+
authentication add `--code`, or pipe the code as the second line).
|
|
166
|
+
- A verification link from `resend-verification` also needs a new password: `auth verify-email` reads
|
|
167
|
+
it from standard input (or asks), sets it, and otherwise prints the `auth password reset-confirm`
|
|
168
|
+
command to run.
|
|
169
|
+
- After `auth login`, `shard` prints who you are, whether the email is verified, your organizations
|
|
170
|
+
and the next step (`shard setup`, or `shard auth verify-email`).
|
|
171
|
+
|
|
172
|
+
## Setup (0.5.0+)
|
|
173
|
+
|
|
174
|
+
`shard setup` makes a signed-in account ready for the workspace commands:
|
|
175
|
+
|
|
176
|
+
1. the organization: `--org`, the saved default, or your only one; with none it creates
|
|
177
|
+
"<your name>'s organization" (`--org-name` to choose); with several it lists them;
|
|
178
|
+
2. the project: `--project`, the saved default, or the organization's only one; with none it creates
|
|
179
|
+
"Default" (`--project-name`);
|
|
180
|
+
3. an API key with every workspace tool (`--tool` repeatable to narrow it), named
|
|
181
|
+
`shard-cli <hostname>` (`--key-name`), saved in the credentials file and checked against the API.
|
|
182
|
+
|
|
183
|
+
It is idempotent: a saved key that still works is kept (`--new-key` makes a new one). It prints what
|
|
184
|
+
it found or created and the next command. The key is never printed; `shard env` prints it for tools
|
|
185
|
+
that read `SHARDFLUX_API_KEY`:
|
|
186
|
+
|
|
187
|
+
```sh
|
|
188
|
+
eval "$(shard env)" # sh, bash, zsh
|
|
189
|
+
shard env --shell fish | source
|
|
190
|
+
shard env --shell powershell | Invoke-Expression
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Organizations, projects, keys, members (0.5.0+)
|
|
194
|
+
|
|
195
|
+
Account commands work on the default organization and project: `--org`/`--project` (an id or a
|
|
196
|
+
slug), else the one saved by `orgs use`, `projects use` or `setup`, else the only one you have.
|
|
197
|
+
With several and no default, the error lists them.
|
|
198
|
+
|
|
199
|
+
```sh
|
|
200
|
+
shard orgs list | create <name> [--slug] [--use] | get [org] | use <org>
|
|
201
|
+
shard orgs export [org] [--out file] # JSON, written 0600 (step-up)
|
|
202
|
+
shard orgs workspaces [org] [--project P] [--state S] [--all] # every project's workspaces, as the dashboard lists them
|
|
203
|
+
shard orgs deletion [org] # what deleting would do, and what blocks it
|
|
204
|
+
shard orgs delete <org> --confirm <slug> --yes # irreversible (step-up)
|
|
205
|
+
shard projects list | create <name> [--slug] [--use] | get <project> | use <project>
|
|
206
|
+
shard api-keys list | create <name> [--tool T]... [--read-only] [--expires 30d|90d|365d|never] [--save] | revoke <id|key_id> --yes
|
|
207
|
+
shard members list | set-role <user|email> <owner|admin|member|billing> | remove <user|email> --yes
|
|
208
|
+
shard invitations list | create <email> --role <role> | revoke <id|email> | accept '<link>' [--use]
|
|
209
|
+
shard templates publish <slug>@<version> | archive <slug>@<version>
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
`api-keys create` prints the new key once, alone on stdout (`KEY=$(shard api-keys create ci)`), with
|
|
213
|
+
what it is on stderr; `--json` includes it as `secret`; `--save` stores it in the credentials file for
|
|
214
|
+
the workspace commands instead of printing it. Revoking the saved key also removes it from the file.
|
|
215
|
+
|
|
216
|
+
## Billing (0.5.0+)
|
|
217
|
+
|
|
218
|
+
```sh
|
|
219
|
+
shard billing plans # public: no sign-in needed
|
|
220
|
+
shard billing status # plan, billing state, period end, pending checkout
|
|
221
|
+
shard billing upgrade <plan> [--open] [--wait] [--timeout 15m]
|
|
222
|
+
shard billing portal [--open] # plan changes, payment methods, invoices, cancellation
|
|
223
|
+
shard billing invoices [--all]
|
|
224
|
+
shard billing alerts [--set 50,80,100 | --clear] # usage alert emails, percent of each allowance
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
`billing upgrade` checks the plan against the public catalog (an unknown one lists the purchasable
|
|
228
|
+
plans), starts Stripe Checkout and prints its URL: a person pays there. `--open` also opens it in the
|
|
229
|
+
default browser (`$BROWSER`, else `xdg-open`, `open` or `start`; best effort). The API activates the
|
|
230
|
+
plan only when Stripe confirms the payment, so `--wait` polls until the subscription is active (exit
|
|
231
|
+
0), the checkout expires or is canceled (exit 6), or `--timeout` runs out (exit 5; the checkout stays
|
|
232
|
+
open). An organization that already has a subscription changes plans in the billing portal: the
|
|
233
|
+
command prints the portal URL instead (exit 0).
|
|
234
|
+
|
|
235
|
+
## Audit, account export and deletion (0.5.0+)
|
|
236
|
+
|
|
237
|
+
```sh
|
|
238
|
+
shard audit list [--action api_key.] [--from 7d] [--to <time>] [--source app|cell_tool] [--outcome denied] [--all]
|
|
239
|
+
shard audit export [--format ndjson|csv] [--out file] [filters] # at most 90 days, 50 000 rows
|
|
240
|
+
shard account status # profile, memberships, deletion state
|
|
241
|
+
shard account export [--out file] # your data as JSON (step-up)
|
|
242
|
+
shard account delete --confirm you@example.com --yes # after a grace period (step-up)
|
|
243
|
+
shard account cancel-deletion
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
`--from`/`--to` take an RFC 3339 time or a duration ago (`90m`, `24h`, `7d`, `2w`). Files `shard`
|
|
247
|
+
writes with exports are created with mode 0600 and never overwritten without `--force`.
|
|
248
|
+
|
|
249
|
+
## Egress and volumes (0.5.0+)
|
|
250
|
+
|
|
251
|
+
These use the project API key, like the other workspace commands.
|
|
252
|
+
|
|
253
|
+
```sh
|
|
254
|
+
shard egress get [--project <id> | --workspace <ws>]
|
|
255
|
+
shard egress set --file policy.json [--project <id> | --workspace <ws>] [--if-version N]
|
|
256
|
+
shard egress history [--project <id> | --workspace <ws>]
|
|
257
|
+
shard egress clear --workspace <ws>
|
|
258
|
+
shard volumes list [--include-org-shared] | create <name> --quota-gib N [--org-shared] | get <id|name>
|
|
259
|
+
shard volumes attach <ws> <volume> --mount /mnt/data [--read-only] | detach <ws> <volume>
|
|
260
|
+
shard volumes attachments <id|name> | delete <id|name> [--force] --yes
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
A policy file is `{"mode": "allow_all" | "allowlist" | "deny_all", "rules": [{"host": "api.github.com",
|
|
264
|
+
"ports": [443]}], "cidrs": []}`. Volume commands wait for the cell unless `--no-wait`.
|
|
265
|
+
|
|
266
|
+
## Credentials file
|
|
267
|
+
|
|
268
|
+
**Changed in 0.5.0: `shard` now stores credentials.** Before 0.5.0 it stored nothing and read the key
|
|
269
|
+
from `SHARDFLUX_API_KEY` on every run. That still works and still wins; the file is only written by
|
|
270
|
+
the commands that sign in or save a key (`auth login`, `auth mfa`, `setup`, `api-keys create --save`,
|
|
271
|
+
and the session renewals of step-up and password changes).
|
|
272
|
+
|
|
273
|
+
- **Where:** `$SHARDFLUX_CONFIG_DIR/credentials.json`, else `$XDG_CONFIG_HOME/shardflux/`, else
|
|
274
|
+
`~/.config/shardflux/` (Windows: `%APPDATA%\shardflux\`).
|
|
275
|
+
- **Protection:** the directory is created with mode 0700 and the file 0600, written atomically (a
|
|
276
|
+
temporary file, then a rename). `shard` warns when the file is readable by others. A file that is not
|
|
277
|
+
valid JSON (or not this format) is never overwritten silently: commands that read it stop with exit 2
|
|
278
|
+
naming it, and a command that writes credentials first moves it to `credentials.json.corrupt-<time>`.
|
|
279
|
+
- **Profiles:** one per API URL, so production, staging and a local API never mix:
|
|
280
|
+
|
|
281
|
+
```json
|
|
282
|
+
{"version": 1, "profiles": {"https://api.shardflux.dev": {
|
|
283
|
+
"session": {"token": "sfu_...", "expires_at": "...", "user": {"id": "...", "email": "..."}, "state": "active"},
|
|
284
|
+
"organization_id": "...", "project_id": "...",
|
|
285
|
+
"api_key": {"token": "sfk_...", "id": "...", "key_id": "...", "project_id": "...", "name": "shard-cli laptop"}}}}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
- **Precedence:** the project API key is `SHARDFLUX_API_KEY`, else the saved `api_key`. The session is
|
|
289
|
+
`SHARDFLUX_SESSION_TOKEN`, else the saved `session`. `shard auth logout` removes the session (the key
|
|
290
|
+
stays); delete the file to forget everything.
|
|
291
|
+
- **Never printed:** the session and the saved key appear only in the file. Output shows key ids; error
|
|
292
|
+
output redacts anything shaped like a key or session token. `shard env` prints the key on purpose.
|
|
293
|
+
|
|
294
|
+
## Version check
|
|
295
|
+
|
|
296
|
+
`shard` tells you when a newer version exists, on stderr after the command's output:
|
|
297
|
+
|
|
298
|
+
```text
|
|
299
|
+
@shardflux/cli 0.5.0 is outdated: 0.6.0 is available. Update: npm install -g @shardflux/cli@latest
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
or that the API no longer supports it (`... is no longer supported by the Shardflux API (minimum
|
|
303
|
+
0.6.0). Update: ...`). It asks `GET /v1/client-versions` at most once a day per API URL (cached in
|
|
304
|
+
`<config dir>/update-check.json`), in parallel with the command: a slow answer is skipped (the next run
|
|
305
|
+
uses it), the exit code never changes, and nothing is printed after a command that failed with
|
|
306
|
+
`--json`. Installed through the `shardflux` npm package it checks `shardflux` instead. `shard version`
|
|
307
|
+
shows the status; `shard version --check` asks now (`--json`: `{"cli", "sdk", "update": {"package",
|
|
308
|
+
"current", "status", "latest", "minimum_supported", "upgrade_command", "checked_at"}}`). Turn it off with
|
|
309
|
+
`SHARDFLUX_NO_UPDATE_CHECK=1` (or `NO_UPDATE_NOTIFIER=1`). The SDK's own check is off inside `shard`.
|
|
310
|
+
|
|
38
311
|
## Environment
|
|
39
312
|
|
|
40
313
|
| Variable | Meaning |
|
|
41
314
|
| --- | --- |
|
|
42
|
-
| `SHARDFLUX_API_KEY` | Project API key (`sfk_<key id>_<secret>`).
|
|
43
|
-
| `
|
|
44
|
-
| `
|
|
315
|
+
| `SHARDFLUX_API_KEY` | Project API key (`sfk_<key id>_<secret>`) for the workspace commands. Default: the key `shard setup` saved. `shard` never accepts a key as an argument (`--api-key`, `--token` and similar flags are refused) and never prints it (except `shard env`); anything shaped like a key is redacted from error output. |
|
|
316
|
+
| `SHARDFLUX_SESSION_TOKEN` | User session (`sfu_...`) for the account commands (0.5.0+). Default: the session `shard auth login` saved. |
|
|
317
|
+
| `SHARDFLUX_API_URL` | API base URL. Default `https://api.shardflux.dev`; `--api-url` overrides it. Plain `http://` is allowed only for loopback hosts. Credentials are saved per API URL. |
|
|
318
|
+
| `SHARDFLUX_CONFIG_DIR` | Directory of `credentials.json` and `update-check.json` (0.5.0+). Default `$XDG_CONFIG_HOME/shardflux`, else `~/.config/shardflux` (`%APPDATA%\shardflux` on Windows). |
|
|
319
|
+
| `SHARDFLUX_NO_UPDATE_CHECK=1` | Never ask whether a newer `shard` exists (0.5.0+; also `true`, `yes`, `on`). `NO_UPDATE_NOTIFIER=1` does the same. |
|
|
320
|
+
| `SHARDFLUX_AGENT_LABEL` | Attribution label for the tool tokens `shard` obtains for exec and files, and the reporting agent of `shard feedback` (0.5.0+). Default `cli`; `--agent-label` overrides it. Each label is one agent session, listed by `shard ws sessions`. |
|
|
45
321
|
| `SHARDFLUX_NO_WAKE=1` | Do not resume a suspended workspace on use; same as `--no-wake` (see "Suspended workspaces" below). `--wake` overrides it. |
|
|
46
322
|
| `SHARDFLUX_WAKE_TIMEOUT_MS` | Longest wait, in milliseconds, for a workspace to wake or finish a transition. Default `120000`; `--wake-timeout <ms>` overrides it. |
|
|
47
323
|
| `SHARDFLUX_HTTP_KEEPALIVE=1` | Reuse HTTP connections (see "HTTP connections" below). |
|
|
48
|
-
|
|
49
|
-
`shard login` stores nothing. There is no config file: the key is read from the environment on
|
|
50
|
-
every run.
|
|
324
|
+
| `BROWSER` | Program `--open` runs with the URL (0.5.0+). Default `xdg-open`, `open` (macOS) or `rundll32` (Windows). |
|
|
51
325
|
|
|
52
326
|
## Commands
|
|
53
327
|
|
|
54
328
|
| Command | What it does |
|
|
55
329
|
| --- | --- |
|
|
56
|
-
| `login`, `
|
|
57
|
-
| `
|
|
58
|
-
| `
|
|
59
|
-
| `
|
|
60
|
-
| `
|
|
61
|
-
| `
|
|
330
|
+
| `auth register\|verify-email\|resend-verification\|login\|mfa\|status\|logout\|sessions\|step-up`, `auth password change\|reset\|reset-confirm`, `auth email change\|confirm`, `auth totp enroll\|confirm\|disable\|recovery-codes` | The account and its sign-in (0.5.0+): see [Accounts and sign-in](#accounts-and-sign-in-050). |
|
|
331
|
+
| `setup [--org O] [--project P] [--org-name N] [--project-name N] [--key-name N] [--tool T]... [--new-key]`, `env [--shell sh\|fish\|powershell]` | Organization, project and a saved API key in one step; the saved key as shell exports (0.5.0+). See [Setup](#setup-050). |
|
|
332
|
+
| `orgs`, `projects`, `api-keys`, `members`, `invitations`, `templates publish\|archive` | Organizations, projects, API keys, members and invitations with the session (0.5.0+). See [Organizations, projects, keys, members](#organizations-projects-keys-members-050). |
|
|
333
|
+
| `billing plans\|status\|upgrade\|portal\|invoices\|alerts` | Plans, Stripe Checkout, the billing portal, invoices and usage alerts (0.5.0+). See [Billing](#billing-050). |
|
|
334
|
+
| `audit list\|export`, `account status\|export\|delete\|cancel-deletion` | The audit log, data exports and account deletion (0.5.0+). |
|
|
335
|
+
| `egress get\|set\|history\|clear`, `volumes list\|create\|get\|delete\|attachments\|attach\|detach` | Outbound network policies and shared volumes with the project key (0.5.0+). |
|
|
336
|
+
| `login`, `whoami` | Show the principal behind the project key (`SHARDFLUX_API_KEY`, else the saved one). |
|
|
337
|
+
| `version [--check]` | Print the CLI and SDK versions and the update status (`--check` asks the API now). |
|
|
338
|
+
| `feedback [--category C] [--workspace W] [--request-id ID] [--error-code CODE] [--command TEXT] [--from-file F\|-] <message...>` | Send feedback straight to the Shardflux founder (0.5.0+). See [Feedback](#feedback-agents-use-this-while-you-work). |
|
|
339
|
+
| `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+). |
|
|
340
|
+
| `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. |
|
|
341
|
+
| `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+). |
|
|
342
|
+
| `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+). |
|
|
62
343
|
| `workspaces inputs <id\|key>` | The workspace's text inputs (0.4.0+). |
|
|
63
|
-
| `workspaces exec <id\|key> [--cwd D] [--env K=V]... [--timeout T] [--stdin F\|-] -- <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. |
|
|
344
|
+
| `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. On a file-first workspace (0.5.0+) the command runs as an execution instead: see [File-first workspaces](#file-first-workspaces). |
|
|
345
|
+
| `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. |
|
|
64
346
|
| `files read <id\|key> <path> [--out F]` | Raw bytes to stdout, or to a local file. |
|
|
65
|
-
| `files write <id\|key> <path> [--from F\|-] [--append] [--no-parents]` | Atomic write. The default source is stdin. |
|
|
347
|
+
| `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). |
|
|
66
348
|
| `files ls <id\|key> <path> [--limit N]` | Directory listing. |
|
|
349
|
+
| `files stat <id\|key> <path> [--revision]` | One path's metadata; `--revision` adds the content's SHA-256 (0.4.0+). |
|
|
350
|
+
| `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.4.0+). |
|
|
351
|
+
| `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.4.0+). `--if-revision` (0.5.0+): file-first workspaces only. |
|
|
67
352
|
| `workspaces suspend\|resume <id\|key> [--wait] [--timeout T] [--timing]` | Lifecycle operation. Returns immediately unless you pass `--wait`. |
|
|
68
353
|
| `workspaces fork <id\|key> <new-key> [caps] [--wait]` | Fork into a new key. |
|
|
69
354
|
| `workspaces delete <id\|key> --yes [--wait]` | Delete the workspace. Tool access ends at once. The key of a persistent workspace is never reused. |
|
|
@@ -97,8 +382,11 @@ every run.
|
|
|
97
382
|
| `templates draft publish <slug> [--state ID] [--description T] [--default-lifetime L] [--acknowledge PATH]... [--no-auto-publish] [--wait]` | Publish the draft as the template's next version. |
|
|
98
383
|
| `templates draft discard <slug> --yes [--wait]` | Delete the draft and end its live test instances. |
|
|
99
384
|
|
|
100
|
-
Aliases: `ws` for `workspaces`, `ops` for `operations`, `
|
|
101
|
-
`
|
|
385
|
+
Aliases: `ws` for `workspaces`, `ops` for `operations`, `execution` for `executions`, `secret` for `secrets`,
|
|
386
|
+
`template` for `templates`, `org`/`organizations` for `orgs`, `project` for `projects`, `keys`/`api-key` for
|
|
387
|
+
`api-keys`, `member` for `members`, `invite`/`invitation` for `invitations`, `volume` for `volumes`.
|
|
388
|
+
`shard workspaces files ...`, `shard workspaces operations ...` and `shard workspaces executions ...` (0.5.0+)
|
|
389
|
+
also work. `<id|key>` is tried as an id when it
|
|
102
390
|
is a UUID. Otherwise, or if no workspace has that id, it is matched as an exact workspace key across every lifetime
|
|
103
391
|
and purpose, so sessions, drafts and test instances resolve too. The live workspace wins over tombstones that ended
|
|
104
392
|
sessions left with the same key.
|
|
@@ -148,12 +436,103 @@ settings:
|
|
|
148
436
|
- A file `shard` cannot read or pack (a symlink that leaves the folder, a device) is refused before any request (exit
|
|
149
437
|
2). The API's refusals (`upload_missing`, `language_unavailable`, `invalid_settings`, ...) exit 2 with the reason.
|
|
150
438
|
|
|
439
|
+
## File-first workspaces
|
|
440
|
+
|
|
441
|
+
(0.5.0+) A file-first workspace has no VM between commands. Its state is a versioned file tree under `/home/user`.
|
|
442
|
+
Each `shard ws exec` runs the command as an *execution*: a fresh VM on the latest tree revision, and the files the
|
|
443
|
+
command changed under `/home/user` become the next revision. Processes, memory and files elsewhere do not survive
|
|
444
|
+
an execution. A file-first workspace is ready at once, never suspended and always persistent, and it needs a layered
|
|
445
|
+
template version. A workspace's mode never changes.
|
|
446
|
+
|
|
447
|
+
```sh
|
|
448
|
+
shard ws open acme/agent-7 --template python-node-browser --mode file-first
|
|
449
|
+
shard files write acme/agent-7 /home/user/app/main.py --from main.py # prints the new tree revision
|
|
450
|
+
shard ws exec acme/agent-7 -v -- python3 /home/user/app/main.py
|
|
451
|
+
shard ws exec acme/agent-7 --execution-id build-42 --timeout 10m -- bash -lc "make -C /home/user/app"
|
|
452
|
+
shard executions get acme/agent-7 build-42 # the recorded result, again
|
|
453
|
+
shard files patch acme/agent-7 /home/user/app/main.py --old "DEBUG = True" --new "DEBUG = False" \
|
|
454
|
+
--if-revision "$(shard ws get acme/agent-7 --json | jq .tree_revision)"
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
`-v` prints what ran on stderr, after the command's own output:
|
|
458
|
+
|
|
459
|
+
```text
|
|
460
|
+
$ shard ws exec acme/agent-7 -v -- bash -lc "python3 app/main.py > app/out.txt"
|
|
461
|
+
execution ex-6f1c2a9e-0d7b-4c1e-9a53-2b8e1f0c4d7a
|
|
462
|
+
state succeeded (exit code 0)
|
|
463
|
+
revision 1 -> 2
|
|
464
|
+
timings blobs_fetched=… exec_ms=… publish_ms=… queue_ms=… run_ms=… total_ms=… vm_seconds=…
|
|
465
|
+
changed 1 path
|
|
466
|
+
A /home/user/app/out.txt
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
- **Exit code**: the command's own once it ran to its end: 124 if it timed out (`--timeout`), 128+N if a signal N
|
|
470
|
+
killed it. An execution that `failed` (it could not run the command, e.g. `exec_failed_to_start`) or was `lost`
|
|
471
|
+
(its host stopped answering, e.g. `lease_expired`) published nothing and exits 6. The error names the reason and
|
|
472
|
+
says `retryable=true|false`; running it again needs a new `--execution-id`.
|
|
473
|
+
- **Output** is printed when the command ended, not streamed: stdout and stderr byte for byte, also when they are not
|
|
474
|
+
UTF-8. `--output-limit <bytes>` keeps at most that much of each (default 1 MiB, at most 16 MiB). A cut stream is
|
|
475
|
+
noted on stderr.
|
|
476
|
+
- **`-v` / `--verbose`**: the execution id, its state and exit status, `base -> new` tree revision (`unchanged` when
|
|
477
|
+
the command changed nothing), `replayed` when this was not the call that ran it, the timings, and the changed paths
|
|
478
|
+
(`A` added, `M` modified, `D` deleted; a directory ends in `/`; the first 100, `--json` lists all). Without `-v`,
|
|
479
|
+
`--timing` prints the timings line alone.
|
|
480
|
+
- **`--json`**: one object, `{execution_id, state, exit_code, term_signal, timed_out, base_revision, tree_revision,
|
|
481
|
+
changed, changed_truncated, stdout, stdout_truncated, stderr, stderr_truncated, replayed, timings, error,
|
|
482
|
+
created_at, finished_at}`. `stdout` and `stderr` are UTF-8 text; a stream that is not valid UTF-8 also has
|
|
483
|
+
`stdout_base64` / `stderr_base64` with the exact bytes.
|
|
484
|
+
- **`--execution-id <id>`**: the execution's idempotency key (8-128 characters of `A-Z a-z 0-9 . _ : -`, starting
|
|
485
|
+
with a letter or digit; default a fresh `ex-<uuid>`). The same id with the same command returns the recorded result
|
|
486
|
+
(`replayed`) instead of running it twice, so a script can repeat the call safely; the same id with another command
|
|
487
|
+
is refused (`execution_id_reused`). `shard` re-sends the request with the same id after a dropped connection and
|
|
488
|
+
after `no_execution_host` (no host had room; `Retry-After`, at most 5 times), and waits within `--wake-timeout` while
|
|
489
|
+
another execution holds the workspace (`execution_in_progress`).
|
|
490
|
+
- **Ctrl-C**: an execution cannot be canceled. Ctrl-C stops waiting (exit 130) and prints the command that fetches the
|
|
491
|
+
result later:
|
|
492
|
+
|
|
493
|
+
```text
|
|
494
|
+
error: Interrupted; execution build-42 keeps running server side if it started (an execution cannot be canceled). [code=interrupted execution_id=build-42]
|
|
495
|
+
hint: fetch its result later with: shard executions get acme/agent-7 build-42
|
|
496
|
+
```
|
|
497
|
+
- **`shard executions get <id|key> <execution-id> [--wait D]`** (also `shard ws executions get`): prints the output and
|
|
498
|
+
the `-v` summary (`--json`: the object above) and exits like `exec`. An execution still queued or running exits 5;
|
|
499
|
+
`--wait 10m` waits up to that long for it to end. Results are kept 7 days.
|
|
500
|
+
- **Not in file-first mode**: `shard` refuses suspend, resume, fork, reset, save-as-template and `workspaces changes`
|
|
501
|
+
without sending them (`not_supported_for_mode`, exit 1, with a hint). Only paths under `/home/user` exist
|
|
502
|
+
(`outside_tree_root`). `--mode file-first` with `--lifetime session` is a usage error (exit 2), and so are
|
|
503
|
+
`--execution-id`, `--output-limit` and `--if-revision` on a processful workspace.
|
|
504
|
+
- **Opening**: reopening a key with the other mode is `mode_mismatch` (exit 1); a deployment that does not offer
|
|
505
|
+
file-first workspaces yet answers `mode_not_available` (exit 2); a template version without layered disks
|
|
506
|
+
`layout_unsupported` (exit 1). Each comes with a hint.
|
|
507
|
+
|
|
508
|
+
### Tree revisions
|
|
509
|
+
|
|
510
|
+
A file-first workspace starts at tree revision 0. Every write, patch or execution that changes files publishes the
|
|
511
|
+
next revision. `shard ws get` shows the current one (`tree_revision` with `--json`), and `files write` and
|
|
512
|
+
`files patch` print the revision after their change (`tree_revision` with `--json`).
|
|
513
|
+
|
|
514
|
+
`--if-revision <n>` on `files write` and `files patch` applies the change only while the tree is at revision n.
|
|
515
|
+
Otherwise nothing changes, `shard` exits 1 and names the revision the tree is at:
|
|
516
|
+
|
|
517
|
+
```text
|
|
518
|
+
error: The workspace's tree is not at the If-Match revision. (tree_revision_mismatch) [code=conflict status=409 request_id=... source=cell]
|
|
519
|
+
hint: the tree is at revision 6 now (another write or execution changed it); nothing changed. Read what you need again, then retry with --if-revision 6
|
|
520
|
+
```
|
|
521
|
+
|
|
151
522
|
## Suspended workspaces
|
|
152
523
|
|
|
153
|
-
`workspaces exec`, `files read|write|ls` and `workspaces changes` wake a suspended workspace:
|
|
154
|
-
resume it (or join the resume or open already running), wait until it runs, then run the request.
|
|
524
|
+
`workspaces exec`, `files read|write|ls|stat|search|patch` and `workspaces changes` wake a suspended workspace:
|
|
525
|
+
they resume it (or join the resume or open already running), wait until it runs, then run the request.
|
|
155
526
|
A request made during a suspend or resume waits for the transition to finish. The request itself
|
|
156
|
-
never runs twice, because the workspace refused it before doing anything.
|
|
527
|
+
never runs twice, because the workspace refused it before doing anything. Since 0.5.0 the wake is one
|
|
528
|
+
request: the API holds the resume until the workspace runs and answers with its tool token (an older
|
|
529
|
+
API is waited for as before).
|
|
530
|
+
|
|
531
|
+
A file-first workspace (0.5.0+) is never suspended, so none of this applies to it.
|
|
532
|
+
|
|
533
|
+
`files read|ls|stat|search` of a suspended workspace whose disk a host still holds are answered from that disk
|
|
534
|
+
without waking it (the state at suspension); `files search` then notes it on stderr (`served_from: "disk"` with
|
|
535
|
+
`--json`).
|
|
157
536
|
|
|
158
537
|
- `--wake-timeout <ms>` (or `SHARDFLUX_WAKE_TIMEOUT_MS`, default `120000`) bounds the wait. Past
|
|
159
538
|
it, `shard` exits 5 and names the operation and its state (for example `Operation <id> (open)
|
|
@@ -213,8 +592,11 @@ Which call is timed:
|
|
|
213
592
|
- `workspaces suspend|resume|fork|delete|close|reset` and `templates draft state|discard`: with `--wait`, the request
|
|
214
593
|
and the whole wait; without it, the request.
|
|
215
594
|
- `operations wait`: the wait.
|
|
216
|
-
- `workspaces exec`, `files read|write|ls` and `workspaces changes`: the wake, when the command had
|
|
217
|
-
suspended workspace. Without a wake nothing is printed.
|
|
595
|
+
- `workspaces exec`, `files read|write|ls|stat|search|patch` and `workspaces changes`: the wake, when the command had
|
|
596
|
+
to wake a suspended workspace. Without a wake nothing is printed.
|
|
597
|
+
- `workspaces exec` on a file-first workspace (0.5.0+): the execution's own timings as the cell reports them
|
|
598
|
+
(`execution <id> timings: blobs_fetched=... exec_ms=... publish_ms=... queue_ms=... run_ms=... total_ms=...`);
|
|
599
|
+
nothing is woken.
|
|
218
600
|
|
|
219
601
|
With `--json`, stdout carries the timing as a `timing` field of the command's JSON instead: `action`, `outcome`,
|
|
220
602
|
`workspace_id`, `operation_id`, `total_ms`, `phases` (`phase`, `reason`, `operation_id`, `start_ms`, `duration_ms`),
|
|
@@ -248,21 +630,47 @@ printf %s "$NEW_KEY" | shard secrets rotate OPENAI_API_KEY
|
|
|
248
630
|
## Output
|
|
249
631
|
|
|
250
632
|
- **Human (default):** aligned tables and key/value blocks on stdout. Errors go to stderr as
|
|
251
|
-
`error: <message> (<reason>) [code=... status=... request_id=... operation_id=...]`, with a
|
|
252
|
-
hint when there is one. A failed operation adds `retryable=true|false` (0.3.1+)
|
|
633
|
+
`error: <message> (<reason>) [code=... status=... request_id=... operation_id=... execution_id=...]`, with a
|
|
634
|
+
hint when there is one. A failed operation adds `retryable=true|false` (0.3.1+), and so does a failed or lost
|
|
635
|
+
execution (0.5.0+). A failure ends with a `feedback: shard feedback ...` line carrying the request id and error
|
|
636
|
+
code (0.5.0+), except the expected flow: usage and validation errors, Ctrl-C, a missing or refused credential, a
|
|
637
|
+
sign-in or step-up to finish, a wait that gave up, and refusals whose hint names the next step.
|
|
253
638
|
- **`--json`:** stdout carries the API's own objects:
|
|
254
639
|
- `workspaces open`/`get` print the workspace view; `list` prints `{data, next_cursor}`.
|
|
255
640
|
- Lifecycle commands print the operation; `fork` prints `{operation, workspace}`.
|
|
256
641
|
- `login`/`whoami` print `{api_url, organization_id, project_id, api_key:{id,key_id}, tool_permissions}`.
|
|
257
642
|
- `exec` prints `{session_id, exit_code, term_signal, timed_out, canceled, stdout, stderr, truncated, reconnects}`.
|
|
258
|
-
|
|
643
|
+
On a file-first workspace (0.5.0+), `exec` and `executions get` print the execution (see
|
|
644
|
+
[File-first workspaces](#file-first-workspaces)).
|
|
645
|
+
- `files read` prints `{path, bytes, content_base64}`; `files write` prints the write result. On a file-first
|
|
646
|
+
workspace `files write` and `files patch` add `tree_revision` (0.5.0+).
|
|
647
|
+
- `files stat` prints the file info (with `revision` when asked); `files search` prints
|
|
648
|
+
`{matches, truncated, stop_reason?, files_scanned, served_from}`; `files patch` prints
|
|
649
|
+
`{path, revision, previous_revision, bytes_written, durable, replacements?, file?}`.
|
|
259
650
|
- `secrets create`/`get`/`update` print the secret's metadata; `list`, `versions` and `access-log`
|
|
260
651
|
print `{data, next_cursor}`; `rotate` prints `{secret, version}`; `delete` prints
|
|
261
652
|
`{deleted, id, name, scope}`; `workspaces secrets` prints `{workspace_id, names, secrets}`.
|
|
653
|
+
- Account commands (0.5.0+) print the API's objects too: lists are `{data, next_cursor}` (with
|
|
654
|
+
`default_organization_id`, `default_project_id` or `saved_api_key_id` where a default applies);
|
|
655
|
+
`auth login`/`auth mfa` print `{status, user, session: {expires_at, credentials_file}, organizations,
|
|
656
|
+
next}` (never the token); `auth status` prints `{api_url, credentials_file, session, api_key, defaults}`;
|
|
657
|
+
`setup` prints `{organization, project, api_key: {id, key_id, name, project_id, tool_permissions},
|
|
658
|
+
created: {organization, project, api_key}, credentials_file, next}`; `api-keys create` prints
|
|
659
|
+
`{api_key, secret, saved: false}` (or `{api_key, saved: true, credentials_file}` with `--save`);
|
|
660
|
+
`billing upgrade` prints `{subscription_exists: false, organization_id, plan_key, checkout, url, opened,
|
|
661
|
+
subscription_active}` or `{subscription_exists: true, organization_id, plan_key, portal_url, opened}`;
|
|
662
|
+
exports print `{export, out, bytes}`; `env` prints `{shell, variables}`; `version` prints
|
|
663
|
+
`{cli, sdk, update}`.
|
|
262
664
|
|
|
263
665
|
Errors go to stderr as `{"error": {code, message, status, request_id, ...}}`. A failed operation is
|
|
264
666
|
`{"error": {"code": "operation_failed", "message", "operation_id", "retryable", "details": {"error_code",
|
|
265
|
-
"reason"}, "operation"}}`; `retryable` (0.3.1+) is the operation error's own flag.
|
|
667
|
+
"reason"}, "operation"}}`; `retryable` (0.3.1+) is the operation error's own flag. A failed or lost execution
|
|
668
|
+
(0.5.0+) is `{"error": {"code": "execution_failed", "message", "execution_id", "retryable", "details": {"reason",
|
|
669
|
+
"error_code", "state"}}}` after the execution on stdout; one still running (`executions get`) is
|
|
670
|
+
`{"error": {"code": "timeout", "message", "execution_id", "last_state"}}`.
|
|
671
|
+
The same failures that print a `feedback:` line add a `"feedback"` field next to `"error"` with that command
|
|
672
|
+
(0.5.0+).
|
|
673
|
+
- `feedback` prints `{id, received_at, duplicate}`.
|
|
266
674
|
- **`--timing`:** the timing goes to stderr after the output. With `--json` it is a `timing` field instead
|
|
267
675
|
(see "Timing").
|
|
268
676
|
|
|
@@ -274,11 +682,11 @@ printf %s "$NEW_KEY" | shard secrets rotate OPENAI_API_KEY
|
|
|
274
682
|
| 1 | error: an API refusal such as `conflict`, `quota_exceeded` or `workspace_not_running`, or a network or protocol failure |
|
|
275
683
|
| 2 | usage error: bad arguments, or input the API rejected as `validation_failed` |
|
|
276
684
|
| 3 | not found: workspace, operation or route |
|
|
277
|
-
| 4 | authentication or authorization: missing, malformed, revoked or insufficient key |
|
|
278
|
-
| 5 | timeout: waiting gave up (`--timeout`, or `--wake-timeout` while waking a workspace); the operation continues server side (`shard operations wait <id>`), a start waiting for capacity for at most 15 minutes |
|
|
279
|
-
| 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 it may succeed later (`capacity_unavailable`) |
|
|
280
|
-
| 130 | interrupted (Ctrl-C). Waits stop at once, and exec sends a cancel to the session. |
|
|
281
|
-
| exec | 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. |
|
|
685
|
+
| 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` |
|
|
686
|
+
| 5 | timeout: waiting gave up (`--timeout`, or `--wake-timeout` while waking a workspace); the operation continues server side (`shard operations wait <id>`), a start waiting for capacity for at most 15 minutes. `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) |
|
|
687
|
+
| 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 it may succeed later (`capacity_unavailable`). Also a file-first execution that ended `failed` or `lost` (0.5.0+): nothing was published. `billing upgrade --wait` (0.5.0+): the checkout expired or was canceled (`checkout_ended`) |
|
|
688
|
+
| 130 | interrupted (Ctrl-C). Waits stop at once, and exec sends a cancel to the session. A file-first execution cannot be canceled: it keeps running, and the error names the `shard executions get` command for its result. |
|
|
689
|
+
| 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. |
|
|
282
690
|
|
|
283
691
|
## HTTP connections
|
|
284
692
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The account plane's command table (0.5.0+; docs/progress/account-cli.md §5): sign-in, setup, organizations,
|
|
3
|
+
* projects, API keys, members, invitations, billing, audit, account export/deletion, plus the project-key commands
|
|
4
|
+
* that were dashboard-only before (egress, volumes) and template publish/archive. Pure data like args.ts, which
|
|
5
|
+
* merges it into COMMANDS.
|
|
6
|
+
*
|
|
7
|
+
* Credentials: commands under auth, orgs, projects, api-keys, members, invitations, billing, audit, account and
|
|
8
|
+
* templates publish|archive use the user session (SHARDFLUX_SESSION_TOKEN, else `shard auth login`'s saved one);
|
|
9
|
+
* egress and volumes use the project API key like the other workspace commands. Secrets never come from arguments:
|
|
10
|
+
* passwords are read from standard input or a no-echo prompt; emailed links are single-use positionals.
|
|
11
|
+
*/
|
|
12
|
+
import type { CommandSpec } from './args.js';
|
|
13
|
+
export declare const ACCOUNT_COMMANDS: CommandSpec[];
|