@tonbo/cli 0.8.0 → 0.10.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.
Files changed (3) hide show
  1. package/README.md +19 -11
  2. package/dist/bin/tonbo.js +797 -118
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -14,9 +14,9 @@ tonbo login [--account <name>]
14
14
  tonbo logout
15
15
  ```
16
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. One login holds one account: log in again to switch accounts. 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.
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
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. The login is saved at `${XDG_CONFIG_HOME:-$HOME/.config}/tonbo/credentials.json` as `{version, account_id, key_id, key, expires_at}`. 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`.
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
20
 
21
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
22
 
@@ -27,7 +27,7 @@ The login and the credentials file are shared with [`yield`](../yield) through `
27
27
 
28
28
  ## Commands and the Management API
29
29
 
30
- Every command other than `login` and `logout` calls one operation of the [Management API](../../contracts/management/openapi-v1.yaml) and is named by that operation's `x-tonbo-cli`; 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.
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
31
 
32
32
  | Command | Operation | Request |
33
33
  | --- | --- | --- |
@@ -60,11 +60,12 @@ Every command other than `login` and `logout` calls one operation of the [Manage
60
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
61
  | `tonbo usage show [--period <YYYY-MM>]` | `getUsage` | `GET /v1/usage` |
62
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>] [-- <command>…]` | `createMachine` | `POST /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
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] [--revision <n>] [-- <command>…]` | `updateMachine` | `PATCH /v1/machines/{name}` |
66
- | `tonbo machine sleep <name>` | `sleepMachine` | `POST /v1/machines/{name}/sleep` |
67
- | `tonbo machine delete <name> [--yes]` | `deleteMachine` | `DELETE /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` |
68
69
  | `tonbo machine shapes` | `listMachineShapes` | `GET /v1/machine-shapes` |
69
70
 
70
71
  ### Output and errors
@@ -166,20 +167,27 @@ tonbo machine create web --image tonbo.dev/platform --port 8080:public --env MOD
166
167
  tonbo machine create worker --image tonbo.dev/platform -- sh -c 'while true; do date; sleep 60; done'
167
168
  tonbo machine update web --env MODE=staging --sleep-after 300
168
169
  tonbo machine sleep web
170
+ tonbo machine activations web
169
171
  tonbo machine delete web
170
172
  ```
171
173
 
172
- 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, every `tonbo machine` command is refused with `region_unavailable`, and the CLI says that nothing was created or changed.
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.
173
175
 
174
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)`.
175
177
 
176
- `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. Without `--shape` it takes the shape `machine shapes` marks as the default. `--port <port>` serves a private port (a member's token or SSH) and `--port <port>:public` an open one, which needs the `machines.public` capability; 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`; `machine show` reports it `active` when it is ready.
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.
177
179
 
178
- `machine update` changes only what its options name. It reads the Machine and writes the change at the revision it read, or at `--revision`, so a change someone made in between is refused with `revision_mismatch` rather than overwritten. `--env` and `--unset-env` change single variables; `--port` replaces every port, naming a public port again keeps its limits, 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 at the Machine's next boot. `machine sleep` puts an awake Machine to sleep now; its next connection wakes it. `machine delete` deletes the Machine with its disk, database and logs, and its name is free for a new Machine at once.
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.
179
187
 
180
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.
181
189
 
182
- A refusal of machine-v2's `errors` prints the server's detail and then what to do next, for example `machine shapes` for `shape_unavailable` or a shorter name for `hostname_too_long`.
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`.
183
191
 
184
192
  ## Usage
185
193