@tonbo/cli 0.10.0 → 0.11.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/README.md +8 -176
- package/dist/bin/tonbo.js +1457 -129
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -7,191 +7,23 @@ npm install --global @tonbo/cli
|
|
|
7
7
|
tonbo --version
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
-
##
|
|
11
|
-
|
|
12
|
-
```console
|
|
13
|
-
tonbo login [--account <name>]
|
|
14
|
-
tonbo logout
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
`login` prints the login URL and opens the browser at `https://tonbo.dev/cli/login`, where you pick the account (your personal account unless `--account` names another) and approve a personal API key named `CLI on <hostname>`. The browser returns a one-time code to a local callback on `127.0.0.1`, and the CLI redeems it with its PKCE verifier for the key. The key acts as you with your role in that account, expires after six months and replaces the key an earlier login on the same host created; there is no refresh, so an expired or revoked key asks you to run `tonbo login` again. `tonbo` acts in the account of the last login: log in again to switch accounts. The file keeps one login key per account of the computer beside it, for `yield` ([`credentials-v1.json`](../../contracts/cli/credentials-v1.json) `accounts`); a key in a non-personal account is named `Yield CLI · <8 hex>` instead of after the host. When no browser can be opened (an SSH session, a server without a desktop), the CLI keeps waiting: open the printed URL in a browser that can reach the callback's `127.0.0.1:<port>` on that machine, through `ssh -L <port>:127.0.0.1:<port>` or the VM's port forwarding.
|
|
18
|
-
|
|
19
|
-
The login and the credentials file are shared with [`yield`](../yield) through `@tonbo/cli-core`: either CLI's `login` signs both in, and either `logout` signs both out, revoking every account's key of the file. The login is saved at `${XDG_CONFIG_HOME:-$HOME/.config}/tonbo/credentials.json` as `{version, account_id, key_id, key, expires_at}`, with `accounts` and `login_secret` beside them. The CLI atomically replaces that file with owner-only permissions and refuses a symlink or a file other users can read. A file written by an earlier CLI release is not migrated; run `tonbo login`.
|
|
20
|
-
|
|
21
|
-
`logout` revokes the saved key through the Management API and removes the file. If the revocation fails, the file is still removed and the CLI reports the key id, so you can revoke it under API keys in the console.
|
|
22
|
-
|
|
23
|
-
### Environment
|
|
24
|
-
|
|
25
|
-
- `TONBO_API_KEY`: a personal key (`tbo_…`) used instead of the saved login, for non-interactive use such as CI. `logout` acts only on the saved login.
|
|
26
|
-
- `TONBO_API_ORIGIN`: the Management API origin, `https://api.tonbo.dev` by default; it must be https (or http on a loopback address). The login page is served from the same origin without its `api.` label.
|
|
27
|
-
|
|
28
|
-
## Commands and the Management API
|
|
29
|
-
|
|
30
|
-
Every command other than `login` and `logout` is named by one operation of the [Management API](../../contracts/management/openapi-v1.yaml) through its `x-tonbo-cli` and calls that operation, plus reads of the same resource (a `--wait`, the Machine a `name_taken` refusal names, or the activations `machine show` reads for the last end); `tonbo machine logs`, once it ships, is the named Streams exception, reading the stream at the Machine's `logs.url`. The command set and the operations tagged with a command are the same set, which `test/commands.test.ts` checks in both directions. The CLI resolves each request from the operation table of the internal package [`@tonbo/cli-core`](../../packages/tonbo-cli-core) (`src/generated/contracts.ts`, which `pnpm --filter @tonbo/cli-core generate:contracts` derives from the contract). `login` and `logout` are the named exception: they obtain and discard the key the other commands present as their Bearer credential. What a command may do is what your role in the logged-in account allows; the CLI never decides it.
|
|
31
|
-
|
|
32
|
-
| Command | Operation | Request |
|
|
33
|
-
| --- | --- | --- |
|
|
34
|
-
| `tonbo account show` | `getAccount` | `GET /v1/account` |
|
|
35
|
-
| `tonbo region list` | `listRegions` | `GET /v1/regions` |
|
|
36
|
-
| `tonbo member list [--limit <n>] [--cursor <c>]` | `listMembers` | `GET /v1/members` |
|
|
37
|
-
| `tonbo member update <member> [--role <role>] [--name <name>]` | `updateMember` | `PATCH /v1/members/{subject}` |
|
|
38
|
-
| `tonbo workspace list [--limit <n>] [--cursor <c>]` | `listGitWorkspaces` | `GET /v1/git/workspaces` |
|
|
39
|
-
| `tonbo agent create <name> [--role <role>] [--region <region>] [--idempotency-key <key>]` | `createAgent` | `POST /v1/agents` |
|
|
40
|
-
| `tonbo api-key list [--limit <n>] [--cursor <c>]` | `listApiKeys` | `GET /v1/api-keys` |
|
|
41
|
-
| `tonbo api-key create <name> [--member <member>] [--read-only] [--bucket <name>]… [--database <name>]… [--database-prefix <prefix>]… [--stream <name>]… [--stream-prefix <prefix>]… [--expires-in <period>]` | `createApiKey` | `POST /v1/api-keys` |
|
|
42
|
-
| `tonbo api-key show <key-id>` | `getApiKey` | `GET /v1/api-keys/{key_id}` |
|
|
43
|
-
| `tonbo api-key revoke <key-id> [--yes]` | `revokeApiKey` | `DELETE /v1/api-keys/{key_id}` |
|
|
44
|
-
| `tonbo bucket list [--limit <n>] [--cursor <c>]` | `listBuckets` | `GET /v1/buckets` |
|
|
45
|
-
| `tonbo bucket create <name> [--region <region>] [--idempotency-key <key>]` | `createBucket` | `POST /v1/buckets` |
|
|
46
|
-
| `tonbo bucket show <name>` | `getBucket` | `GET /v1/buckets/{name}` |
|
|
47
|
-
| `tonbo bucket update <name> (--public \| --private)` | `updateBucket` | `PATCH /v1/buckets/{name}` |
|
|
48
|
-
| `tonbo bucket delete <name> [--yes]` | `deleteBucket` | `DELETE /v1/buckets/{name}` |
|
|
49
|
-
| `tonbo database list [--prefix <prefix>] [--limit <n>] [--cursor <c>]` | `listDatabases` | `GET /v1/databases` |
|
|
50
|
-
| `tonbo database create <name> [--region <region>] [--expires-at <time> \| --expires-in <duration>] [--idempotency-key <key>]` | `createDatabase` | `POST /v1/databases` |
|
|
51
|
-
| `tonbo database show <name>` | `getDatabase` | `GET /v1/databases/{name}` |
|
|
52
|
-
| `tonbo database update <name> (--public \| --private)` | `updateDatabase` | `PATCH /v1/databases/{name}` |
|
|
53
|
-
| `tonbo database delete <name> [--yes]` | `deleteDatabase` | `DELETE /v1/databases/{name}` |
|
|
54
|
-
| `tonbo database usage [--period <YYYY-MM>] [--sort list_value\|name] [--prefix <prefix>] [--names <a,b>] [--limit <n>] [--cursor <c>]` | `listDatabaseUsage` | `GET /v1/usage/databases` |
|
|
55
|
-
| `tonbo stream list [--prefix <prefix>] [--limit <n>] [--cursor <c>]` | `listStreams` | `GET /v1/streams` |
|
|
56
|
-
| `tonbo stream create <name> [--region <region>] [--content-type <type>] [--expires-at <time> \| --expires-in <duration>] [--idempotency-key <key>]` | `createStream` | `POST /v1/streams` |
|
|
57
|
-
| `tonbo stream show <name>` | `getStream` | `GET /v1/streams/{name}` |
|
|
58
|
-
| `tonbo stream update <name> (--public \| --private)` | `updateStream` | `PATCH /v1/streams/{name}` |
|
|
59
|
-
| `tonbo stream delete <name> [--yes]` | `deleteStream` | `DELETE /v1/streams/{name}` |
|
|
60
|
-
| `tonbo stream usage [--period <YYYY-MM>] [--sort list_value\|name] [--prefix <prefix>] [--names <a,b>] [--limit <n>] [--cursor <c>]` | `listStreamUsage` | `GET /v1/usage/streams` |
|
|
61
|
-
| `tonbo usage show [--period <YYYY-MM>]` | `getUsage` | `GET /v1/usage` |
|
|
62
|
-
| `tonbo machine list [--limit <n>] [--cursor <c>]` | `listMachines` | `GET /v1/machines` |
|
|
63
|
-
| `tonbo machine create <name> --image <reference> [--shape <shape>] [--region <region>] [--port <port[:access]>]… [--default-port <port>] [--env <KEY=VALUE>]… [--sleep-after <seconds>] [--idle-action <action>] [--stop-grace <seconds>] [--idempotency-key <key>] [--wait [--timeout <seconds>]] [-- <command>…]` | `createMachine` | `POST /v1/machines` |
|
|
64
|
-
| `tonbo machine show <name>` | `getMachine` | `GET /v1/machines/{name}` |
|
|
65
|
-
| `tonbo machine update <name> [--image <reference>] [--image-command] [--shape <shape>] [--port <port[:access]>]… [--clear-ports] [--default-port <port>] [--env <KEY=VALUE>]… [--unset-env <KEY>]… [--sleep-after <seconds>] [--idle-action <action>] [--stop-grace <seconds>] [--discard-snapshot] [--if-match <etag>] [-- <command>…]` | `updateMachine` | `PATCH /v1/machines/{name}` |
|
|
66
|
-
| `tonbo machine sleep <name> [--if-match <etag>] [--wait [--timeout <seconds>]]` | `sleepMachine` | `POST /v1/machines/{name}/sleep` |
|
|
67
|
-
| `tonbo machine delete <name> [--yes] [--if-match <etag>]` | `deleteMachine` | `DELETE /v1/machines/{name}` |
|
|
68
|
-
| `tonbo machine activations <name> [--limit <n>] [--cursor <c>]` | `listMachineActivations` | `GET /v1/machines/{name}/activations` |
|
|
69
|
-
| `tonbo machine shapes` | `listMachineShapes` | `GET /v1/machine-shapes` |
|
|
70
|
-
|
|
71
|
-
### Output and errors
|
|
72
|
-
|
|
73
|
-
Every command prints an aligned table or a list of fields for people. With `--json` it prints the answer's `data` exactly as the API returned it, one JSON value on stdout and nothing else there. A list prints one page; when there is another, the CLI writes `More results: run again with --cursor <cursor>` to stderr, so `--json` output stays the API's `data`. `database usage --json`, `stream usage --json` and `machine shapes --json` print the whole answer, since the usage's `other` row, checkpoint and prices, and the default shape, belong with the rows. `--limit` asks for up to that many items (the API's default is 50, its maximum 200).
|
|
74
|
-
|
|
75
|
-
A refusal prints the problem's detail, the fields a validation error names, and the request's `X-Request-Id` to stderr, and the command exits with status 1. An invalid or expired key adds `Run tonbo login`.
|
|
76
|
-
|
|
77
|
-
### Retried creations
|
|
78
|
-
|
|
79
|
-
`agent create`, `bucket create`, `database create`, `stream create` and `machine create` send an `Idempotency-Key`, a new UUID unless `--idempotency-key` names one. When a creation is not confirmed (the network failed or the server answered 5xx), the CLI prints its key; retrying with that key and the same arguments returns what the first request created instead of creating a second one. `api-key create` has no idempotency key, because a key's secret is never stored and a replay could not return it; a live key's name is unique, so a blind retry is refused with 409 rather than creating a second key.
|
|
80
|
-
|
|
81
|
-
### Destructive commands
|
|
82
|
-
|
|
83
|
-
`api-key revoke`, `bucket delete`, `database delete`, `stream delete` and `machine delete` ask before they act when stdin and stderr are a terminal: a revocation is confirmed by typing `yes`, a deletion by typing the bucket's, database's, stream's or Machine's name, as in the console. Without a terminal they refuse unless `--yes` is given.
|
|
84
|
-
|
|
85
|
-
## Account
|
|
86
|
-
|
|
87
|
-
`account show` prints the logged-in account: its id, name and kind, your member subject and role in it, and its limits.
|
|
88
|
-
|
|
89
|
-
## Regions
|
|
90
|
-
|
|
91
|
-
`region list` shows the regions new resources can be created in, with each region's data-plane origin.
|
|
92
|
-
|
|
93
|
-
## Members and Agents
|
|
94
|
-
|
|
95
|
-
```console
|
|
96
|
-
tonbo member list
|
|
97
|
-
tonbo member update pi-live --role admin
|
|
98
|
-
tonbo member update agent.80000000-0000-4000-8000-000000000003 --name pi-next
|
|
99
|
-
tonbo agent create my-agent --region us-east-1
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
`member list` lists the account's people and Agents with their kind, name and role. `member update` gives a member another role (`owner`, `admin` or `member`; only an owner grants `owner`) or renames an Agent with `--name`, or both at once. `<member>` is a member subject: a person's user id, or `agent.<agent id>` for an Agent. An Agent's bare id or its name works too: the CLI looks it up in `member list` and uses it only when exactly one member matches.
|
|
103
|
-
|
|
104
|
-
`agent create` creates an Agent identity with a role (`member` unless `--role` names another). Every Agent has a home region, chosen when it is created and never changed afterwards. Without `--region`, Tonbo uses the only region that accepts new Agents; when several do, an interactive `agent create` asks which one to use, and a non-interactive request without `--region` is refused.
|
|
105
|
-
|
|
106
|
-
## Git workspaces
|
|
107
|
-
|
|
108
|
-
```console
|
|
109
|
-
tonbo workspace list
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
`workspace list` lists the account's git workspaces, the default first: each one's id, name, whether it is the default, its region and where gitd serves it (`<git origin>/<ws_hex>`, the prefix of every repository URL in it). Every account has a default workspace from its creation. Listing needs only a role on the account; it admits nothing, and every git token is still admitted when it is minted.
|
|
113
|
-
|
|
114
|
-
## API keys
|
|
115
|
-
|
|
116
|
-
```console
|
|
117
|
-
tonbo api-key list
|
|
118
|
-
tonbo api-key create ci-reader --member pi-live --read-only --bucket events --expires-in 6_months
|
|
119
|
-
tonbo api-key revoke 70000000-0000-4000-8000-000000000007
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
`api-key list` shows your keys, or every key of the account for an owner or admin, with the last four characters of each secret. `api-key create` creates a personal key for you, or with `--member` a key of an Agent (its subject, id or name; owners and admins only). `--read-only`, and either `--bucket` or any of `--database`, `--database-prefix`, `--stream` and `--stream-prefix` (repeat each for several), narrow the key for its whole life; a key narrowed to databases and streams reaches both, and `api-key list` and `api-key show` print what each key reaches of each; `--expires-in` is one of `15_days`, `1_month`, `6_months`, `1_year` or `never` (the default). The secret is printed once, in that answer only, with a warning on stderr: store it then, because no command can show it again. Without `--json`, the answer also carries a ready-to-paste `TONBO_API_KEY=<secret>` line on stdout, beside the secret, for your application's environment (a `.env` file or a secret store), and stderr notes that `TONBO_API_KEY` in your own shell overrides your `tonbo login`, for this CLI too. stderr never carries the secret, and `--json` prints only the answer. `api-key show` prints one key, and `api-key revoke` revokes it and every token minted from it.
|
|
123
|
-
|
|
124
|
-
## Buckets
|
|
125
|
-
|
|
126
|
-
```console
|
|
127
|
-
tonbo bucket create events --region us-east-1
|
|
128
|
-
tonbo bucket update events --public
|
|
129
|
-
tonbo bucket delete events
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
`bucket list` and `bucket show` print each bucket's region, state, read access and URL; a stream lives at `{url}/{stream}`. `bucket create` creates a bucket in `--region`, or in the account's default region. `bucket update` publishes a bucket for anonymous reads with `--public` or takes it private with `--private`. `bucket delete` deletes a bucket and every stream in it; the bucket's name is never used again.
|
|
133
|
-
|
|
134
|
-
## Databases
|
|
10
|
+
## Usage
|
|
135
11
|
|
|
136
12
|
```console
|
|
13
|
+
tonbo login
|
|
137
14
|
tonbo database create notes
|
|
138
|
-
tonbo database
|
|
139
|
-
tonbo database show notes
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
`database create` creates a database in `--region`, or in the default region, and prints its fields with its URL. `--expires-at` and `--expires-in` give it an expiry fixed for its life, by the same rules as `stream create`'s: once it passes, Tonbo deletes the database within a minute, as `database delete` would, and its name is free again; `database show` prints it, and without either the database never expires. A Machine's database never expires. Without `--json` it then writes the next step to stderr, opening the database by name from code:
|
|
143
|
-
|
|
144
|
-
```text
|
|
145
|
-
Next: npm i --save-exact @tonbo/sqlite-ursula@0.11.2
|
|
146
|
-
open("notes") from "@tonbo/sqlite-ursula/tonbo"
|
|
15
|
+
tonbo database list --json
|
|
147
16
|
```
|
|
148
17
|
|
|
149
|
-
`
|
|
18
|
+
`tonbo --help` prints the rules every command shares (output and `--json`, pages, exit status, keys and the login file, retried creations, destructive commands) and the environment variables the CLI reads; `tonbo <command> --help` prints what one command does, its arguments, each flag with its default, and an example. The same words, with the operation each command calls and what its `--json` prints, are the CLI reference at [tonbo.dev/docs/reference/cli](https://tonbo.dev/docs/reference/cli).
|
|
150
19
|
|
|
151
|
-
|
|
20
|
+
The login and the credentials file are shared with [`yield`](../yield) through `@tonbo/cli-core`, by the contract [`credentials-v1.json`](../../contracts/cli/credentials-v1.json).
|
|
152
21
|
|
|
153
|
-
|
|
154
|
-
tonbo stream create events --content-type application/json
|
|
155
|
-
tonbo stream create run-42 --content-type application/json --expires-in 24h
|
|
156
|
-
tonbo stream show events
|
|
157
|
-
tonbo api-key create run-reader --read-only --stream-prefix run-
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
`stream create` creates a raw durable stream in `--region`, or in the default region, with the content type every append must send (`--content-type`, `application/octet-stream` by default; one lowercase `type/subtype` without parameters), and prints its fields with its URL on the region's Streams origin. A stream and a database may share a name; each kind has its own names, limit and usage (`stream usage`, whose `other` holds the account's databases and everything else, as `database usage`'s holds its streams). Without `--json` it then writes the next step to stderr: append with `POST` to the URL and read with `GET` from `?offset=-1`, with any Durable Streams client. `--expires-at` (an RFC 3339 time, at least 60 seconds after the creation) or `--expires-in` (`90s` or more, such as `30m`, `24h` or `7d`, counted from now) gives the stream an expiry fixed for its life: once it passes, Tonbo deletes the stream within a minute, as `stream delete` would, and its name is free again; `stream show` prints it, and without either the stream never expires. `--expires-in` is counted from when the command runs, so it never goes with `--idempotency-key`: an unconfirmed creation with an expiry prints a retry hint naming its key and the absolute time it sent, and the retry passes that time with `--expires-at` (the same for `database create`). A key narrowed to streams (`api-key create --stream` or `--stream-prefix`) reaches only those streams; a key narrowed to buckets, or by name to databases alone, reaches no stream.
|
|
161
|
-
|
|
162
|
-
## Machines
|
|
163
|
-
|
|
164
|
-
```console
|
|
165
|
-
tonbo machine shapes
|
|
166
|
-
tonbo machine create web --image tonbo.dev/platform --port 8080:public --env MODE=prod
|
|
167
|
-
tonbo machine create worker --image tonbo.dev/platform -- sh -c 'while true; do date; sleep 60; done'
|
|
168
|
-
tonbo machine update web --env MODE=staging --sleep-after 300
|
|
169
|
-
tonbo machine sleep web
|
|
170
|
-
tonbo machine activations web
|
|
171
|
-
tonbo machine delete web
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
A Machine is a VM booted from an image, in one region, with its own database (`contracts/machines/machine-v2.json`). Machines open by invitation: until a region is open for them, `machine create`, `update`, `sleep` and `delete` are refused with `region_not_offered`, and the CLI says that nothing was created or changed; `machine list`, `show` and `shapes` still answer. A region that cannot be reached is refused with `region_unavailable`, whose `Retry-After` says when a retry may clear it.
|
|
175
|
-
|
|
176
|
-
The image is `tonbo.dev/platform`, the platform image each node release ships, or, once registry images are offered, a public OCI image with a linux/arm64 variant. Until then any other reference is refused with `image_not_offered`, before anything is created or changed; `machine show` prints the platform image as `tonbo.dev/platform (platform image)`.
|
|
177
|
-
|
|
178
|
-
`machine create` resolves a registry image to its linux/arm64 digest (the platform image resolves to none) and reserves the Machine's name and its hostnames: `https://<name>-<account>.<region>.tonbo.sh` for the default port, and `<name>.<account>@<region>.tonbo.sh` for SSH, which `machine show` marks as not served yet. Without `--shape` it takes the shape `machine shapes` marks as the default. `--port <port>` serves a private port (a member's token) and `--port <port>:public` an open one, which needs the `machines.public` capability and has no wake-rate, concurrency or runtime limit; the first port is served at the hostname unless `--default-port` names another. A command after `--` replaces the image's CMD. The answer is the Machine while it is `creating`. With `--wait` the CLI reads the Machine at its `Location` after the answer's `Retry-After`, and again every `creation.poll_after_seconds`, until it is `active` or `failed` or `--timeout` (300 s by default) passes; a failure prints the Machine's failure with what to do and exits non-zero, and a timeout says it is still creating and undoes nothing. A create the network or a 5xx answer did not confirm is retried in the command with the same idempotency key, at most three times, honouring `Retry-After`; a `name_taken` refusal says which Machine holds the name and how old it is, in case it is yours from a lost reply.
|
|
179
|
-
|
|
180
|
-
`machine create` and `machine update` warn on stderr when the Machine ends up with no port (nothing can wake it until exec and SSH arrive) and when an `--env` key looks secret (`*_KEY`, `*_TOKEN`, `*SECRET*`, `*PASSWORD*`): env values are readable by every member through the API, and Machine secrets come later. When the default port is private, `machine create` and `machine show` print the `curl` call that reaches it with a personal key, and say that on a private port Tonbo authenticates the caller, so the app sees neither `Authorization` nor who called; an app with its own users serves a public port and does its own auth.
|
|
181
|
-
|
|
182
|
-
`machine show` prints the state and what it means (an `active` Machine that is asleep boots on its first request, which the edge holds while it boots), the live activation and conditions when there are any, when the Machine sleeps and that its disk resets at every sleep until suspend ships, the database and logs URLs, a link to the durability text (the CLI prints the link only, never the text or a paraphrase of it), the ETag and who created the Machine. Each condition comes with what to do: a refused wake (`wake_blocked`) names its reason, when it was first refused and, for a crash backoff, when a retry may pass; `creation_delayed` says the creation is taking longer than usual and goes on. For an `active` Machine, `machine show` also reads its newest activations and prints how the last one ended (`Last end`), and when the live activation was admitted at an older revision than the Machine's it prints `Spec N, admitted at M` and says that ports and sleep-after already apply and that a changed image, command, shape or env applies after `tonbo machine sleep <name>`, since every spec change advances the revision. `machine show` prints image states as the API answers them: `pulling`, `ready`, `failed` or `not_pulled`. `machine list` prints each Machine's conditions in its last column.
|
|
183
|
-
|
|
184
|
-
`machine activations` lists a Machine's activations, newest first: the wake, what woke it, the spec revision and shape it ran, when it started and how it ended (its state, the reason such as `idle_early`, `workload_exited` with the exit code, or a refusal such as `payment_required`), or `live`.
|
|
185
|
-
|
|
186
|
-
`machine update` changes only what its options name. It reads the Machine and sends the ETag it read, or `--if-match`'s, so a change someone made in between, or another Machine that took the name, is refused with `precondition_failed` rather than overwritten; a Machine whose creation failed is refused with `machine_failed`. `--env` and `--unset-env` change single variables; `--port` replaces every port, and the current default port stays the default while it is still listed unless `--default-port` names another. Ports and `--sleep-after` apply at once; image, command, shape and env apply at the next activation, and the command says how to apply them now: `machine sleep`, after which the next request boots the new spec; naming the same tag again re-resolves its digest. `machine sleep` puts an awake Machine to sleep now, and says so when it is already asleep or still creating; with `--wait` it reads the Machine after the answer's `Retry-After`, and again every `sleep.poll_after_seconds`, until it is asleep or `--timeout` (300 s by default) passes. `machine delete` sends the ETag it read when it asked for confirmation, and `machine sleep` and `machine delete` send `--if-match`'s when given. `--if-match` takes the ETag `machine show` prints, with or without its double quotes: a value with neither a leading `"` nor `W/"` is quoted again, since a shell drops the quotes of a pasted tag. `machine shapes` prints each shape's list price for an hour at full use. `machine delete` deletes the Machine with its disk, database and logs, and its name is free for a new Machine at once.
|
|
187
|
-
|
|
188
|
-
In a personal account, `machine list`, `machine show` and `machine delete` also cover your own computers, which `yield login` registers (Machines of kind `byoc`, which run nothing Tonbo operates). They are served even while Machines are not open in any region. `machine list` prints them in a second table with their system, agent harnesses, when they last reported and the state of their login key; `machine show` adds the hostname and device id, which only you see. `machine delete` forgets a computer: it disappears from the list at once and its name is free once the forget completes. Forgetting does not revoke the computer's key, so a computer whose key is still active registers again at its next start; the command says so and suggests `yield logout` on it or `tonbo api-key revoke` first. An organization lists managed Machines only.
|
|
189
|
-
|
|
190
|
-
A refusal of machine-v2's `errors`, or of a shared code such as `region_not_offered`, `precondition_required` or `precondition_failed`, prints the server's detail and then what to do next, for example `machine shapes` for `shape_not_offered` or a shorter name for `hostname_too_long`.
|
|
22
|
+
## Commands and the Management API
|
|
191
23
|
|
|
192
|
-
|
|
24
|
+
Every command other than `login` and `logout` is named by one operation of the [Management API](../../contracts/management/openapi-v1.yaml) through its `x-tonbo-cli` and calls that operation, plus reads of the same resource (a `--wait`, the Machine a `name_taken` refusal names, the activations `machine show` reads for the last end, or the Volume a `machine create` or `update --volume` names, read for its id and region); `tonbo machine logs`, once it ships, is the named Streams exception, reading the stream at the Machine's `logs.url`. The command set and the operations tagged with a command are the same set, which `test/commands.test.ts` checks in both directions. The CLI resolves each request from the operation table of the internal package [`@tonbo/cli-core`](../../packages/tonbo-cli-core) (`src/generated/contracts.ts`, which `pnpm --filter @tonbo/cli-core generate:contracts` derives from the contract). `login` and `logout` are the named exception: they obtain and discard the key the other commands present as their Bearer credential. What a command may do is what your role in the logged-in account allows; the CLI never decides it.
|
|
193
25
|
|
|
194
|
-
`
|
|
26
|
+
The help lives with the commands: [`src/app.ts`](src/app.ts) defines each command, its arguments and flags with their one-line descriptions, and [`src/help.ts`](src/help.ts) holds the long help, each flag's default, the examples, the shared rules and the environment. [`commands.json`](commands.json) is all of it as `--help` prints it, which the docs' CLI reference renders; `test/commands.test.ts` holds it to the program, and holds every runnable command to its details and example and the environment list to the variables the code reads, so after changing a command run `pnpm --filter @tonbo/cli commands`.
|
|
195
27
|
|
|
196
28
|
## Related design
|
|
197
29
|
|