# The `clicked` CLI

For agents with a shell, and for people. Node 20 or newer, no other dependencies. It uses your own `ssh` and `rsync`.

## Install
It is served from clicked.cloud, not the npm registry: no npm or GitHub account needed. https://clicked.cloud/cli/latest.json names the current version, its URL and sha256.
```sh
npm install -g https://clicked.cloud/cli/clicked-0.1.0.tgz
```

## Sign in
```sh
clicked login                 # opens your browser: sign in with the emailed link, click Allow (OAuth, PKCE S256, loopback redirect)
clicked login --token ck_…    # or a ck_ token from the dashboard's Account → Security tab; this lands in your shell history
```
Either is saved to `~/.config/clicked/config.json` with mode 0600. A browser login keeps a 1-hour access token and a rotating refresh token, refreshed for you; disconnect it in Account → Security → Connected apps. `CLICKED_TOKEN` in the environment overrides it (good for CI and agents). `CLICKED_API_URL` overrides the API (default `https://clicked.cloud`); the token is only sent over https, or to localhost.

## Commands
Every command takes `--json`: one JSON object on stdout, errors as `{"error":"…","message":"…"}` with exit code 1. Progress from ssh and rsync goes to stderr.

| Command | Does |
|---|---|
| `clicked whoami` | The account's email |
| `clicked sites` | Your sites: domain, status, live release, id |
| `clicked deploy <dir> [--site <domain\|id>] [--allow-secrets]` | Uploads `<dir>` to `releases/<RELEASE_ID>/`, registers it, puts it live; prints the live URL and time taken |
| `clicked rollback [--site <domain\|id>]` | Puts the previous release back live |
| `clicked keys add [path.pub] [--site …] [--name …] [--yes]` | Adds a public key (default `~/.ssh/id_ed25519.pub`; offers ssh-keygen if missing, `--yes` to skip asking) |
| `clicked domains search <name>` | Available names and yearly prices |
| `clicked dns list <domain>` | DNS records |
| `clicked dns set <domain> <A\|AAAA\|CNAME\|MX\|TXT> <host> <value> [--ttl n] [--priority n]` | Adds a record (`@` = the domain itself). MX records need the person signed in at clicked.cloud, so a token gets `403` for MX |
| `clicked preview <dir> [--email you@…] [--token pvt_…] [--allow-secrets]` | **No account needed, just a verified email.** The first time, asks for the email (or takes `--email`), has us email a link, and asks you to paste the `pvt_` token the link's page shows; saves it to `~/.config/clicked/preview-token.json` (0600) for 30 days. Then packs `<dir>` as tar.gz, uploads a free 7-day preview, prints `url`, `expiresAt`, `claimUrl`; saves the delete token to `~/.config/clicked/previews.json` (0600). See [previews.md](previews.md) |
| `clicked preview delete <id>` | Deletes a preview early with its saved token |

`--site` can be left out when the account has exactly one site. `preview` needs no `ck_` token: it sends only its `pvt_` preview token (`--token`, else `CLICKED_PREVIEW_TOKEN`, else the saved one) to `CLICKED_PREVIEW_URL` (default `https://clickedpreview.uk`), and never sends your `ck_` token there. A token the service refuses (expired or revoked) is forgotten, so the next run asks again. An agent with no terminal prompt can run `clicked preview <dir> --email you@…`, ask the human for the token, then `clicked preview <dir> --token pvt_…`.

## What `deploy` runs
With `RELEASE_ID` = UTC now (`20261108T091500Z`):

```sh
ssh -p 22 -o BatchMode=yes -o ConnectTimeout=15 -o StrictHostKeyChecking=accept-new <user>@ssh.gb.stackcp.com mkdir -p releases/<RELEASE_ID>
rsync -az --exclude=.git -e 'ssh -p 22 -o BatchMode=yes -o ConnectTimeout=15 -o StrictHostKeyChecking=accept-new' <dir>/ <user>@ssh.gb.stackcp.com:releases/<RELEASE_ID>/
```
then, only if both exited 0, `POST /api/sites/:id/releases {releaseId}` and `POST /api/sites/:id/activate {releaseId}`. A failed mkdir or rsync stops there: nothing is registered or activated.

## Secrets
`deploy` and `preview` refuse a folder containing any of these, anywhere inside it, unless you pass `--allow-secrets`:
- `.env`, `.env.*`, any case (except `.env.example`, `.env.sample`, `.env.template`)
- `.envrc`, `.dev.vars`, `.aws/credentials`
- `*.pem`, `*.key`, `*.p12`, `*.pfx`, `*.kdbx`
- SSH private keys: `id_rsa`, `id_dsa`, `id_ecdsa`, `id_ed25519` (and `_sk` variants)
- `.npmrc`, `.git-credentials`

`.git/` is never uploaded.

## Errors you may see
| Error | Means |
|---|---|
| `secrets` | The folder has a file above. Remove it from the build. |
| `upload` | ssh or rsync failed. A new key takes about 10 minutes; see [ssh-keys.md](ssh-keys.md). |
| `conflict` | The site is still being set up, or there is nothing to roll back to. |
| `not_found` | No such site or domain on this account. |
| `unauthorized` | No token, or it was revoked. Run `clicked login`. |
