# Developer CLI

The first-party `simhealth` CLI logs in like `gcloud` or `stripe`, then runs the
core loop: pick a project, edit the dictionary, sample records. It is an HTTP
client only. Wallet top-up, API key screens, and admin stay on the website.

## Install

macOS and Linux (detects OS/arch, verifies SHA-256, installs to
`~/.local/bin/simhealth` or `/usr/local/bin` if writable):

```bash
curl -fsSL https://simdata.interoperabilitypro.com/install.sh | bash
```

Windows (PowerShell; installs to `%LOCALAPPDATA%\simhealth\bin`):

```powershell
irm https://simdata.interoperabilitypro.com/install.ps1 | iex
```

Binaries come from a public GCS bucket (`latest.json` at
`https://storage.googleapis.com/simhealth-cli/latest.json`). The GitHub
repository is private; do not use GitHub Release assets. Override the catalog
URL with `SIMHEALTH_UPDATE_BASE_URL` (tests and mirrors).

## Update

```bash
simhealth update --check
simhealth update
simhealth update --json
```

`simhealth update` compares this binary's version to `latest.json`, downloads
the matching archive, verifies SHA-256, and replaces the running binary.
`--json` prints `{ "current", "latest", "updated" }`. Already-current exits 0.
Checksum or replace failures exit non-zero.

## Contributor build

Rust is only required to change the CLI itself:

```bash
cargo install --path cli --locked
```

## Host

Default host is production: `https://api.simdata.interoperabilitypro.com`.

```bash
simhealth --host https://api.preprod.simhealth.interoperabilitypro.com login
simhealth --host http://127.0.0.1:8090 login
```

`SIMHEALTH_HOST` is the same override.

## Login

`simhealth login` opens a browser and completes authorization code + PKCE
(RFC 6749 / 7636) on `http://127.0.0.1:{port}/callback`. The public client id
is `simhealth-cli` (no secret). PKCE S256 is required.

`simhealth login --no-browser` uses the RFC 8628 device grant: it prints a URL
and user code, then polls `POST /oauth/token`. Device grant is also used when
the CLI cannot open a browser.

`simhealth logout` calls `POST /oauth/revoke` and deletes the credential file.
`simhealth auth status` is `GET /v1/me`. `simhealth auth token` prints a fresh
access token (refreshing if needed) for scripts.

## Credential files

Files are mode `0600` under **`~/.config/simhealth/`** (or
`$XDG_CONFIG_HOME/simhealth`):

| File | Contents |
| --- | --- |
| `credentials.json` | host, email, access token, refresh token, expiry |
| `config.json` | selected project |

`SIMHEALTH_CONFIG_DIR` replaces that directory (used by tests). Other env
overrides: `SIMHEALTH_HOST`, `SIMHEALTH_PROJECT`, `SIMHEALTH_TOKEN`.

## Commands

Every command accepts `--json` and exits `0` on success. HTTP `401`, `402`,
`403`, and `404` use that status as the exit code. Network and other errors
exit `1`.

| Command | HTTP |
| --- | --- |
| `simhealth projects list` | `GET /v1/projects` |
| `simhealth projects create NAME` | `POST /v1/projects` |
| `simhealth projects use ID` | `GET /v1/projects/{id}` then write `config.json` |
| `simhealth dictionary get` | `GET /v1/projects/{id}/catalog` |
| `simhealth dictionary get --kind K --id E` | `GET /v1/projects/{id}/catalog/{kind}/{id}` |
| `simhealth dictionary validate FILE` | `POST /v1/projects/{id}/catalog/validate` |
| `simhealth dictionary publish FILE` | `POST .../catalog/batch` when the JSON has `entries`; otherwise `PUT .../catalog/{kind}/{id}` |
| `simhealth sample RECORD --count --seed --format json\|ndjson\|avro` | `GET /v1/projects/{id}/random/{record}` |
| `simhealth account` | `GET /v1/me` and `GET /v1/billing/transactions` |

Sample `--format` sets `Accept` to `application/json`, `application/x-ndjson`,
or `application/avro-binary`. Extra `--constraint key=value` (or leftover
`key=value` args) become query parameters. The same `--seed` replays for the
current dictionary version.

Publish mapping is thin: a file `{"entries":[...]}` is a batch publish; a file
with `kind`, `id`, and `source` (or `--kind` / `--id` plus `source`) is a
single PUT.

```bash
simhealth login
simhealth projects list --json
simhealth projects use default
simhealth dictionary get
simhealth sample person --count 1 --seed 1842 --format json
```
