@alter-ai/cli 0.1.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 +208 -0
- package/dist/cli.d.ts +76 -0
- package/dist/cli.js +12466 -0
- package/package.json +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# `@alter-ai/cli` — the Alter Vault command-line interface
|
|
2
|
+
|
|
3
|
+
`alter` is a command-line client for the Alter Vault dev portal. It authenticates with a Personal Access Token (PAT) minted from the dashboard and exposes the same dashboard operations as scriptable commands.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @alter-ai/cli
|
|
9
|
+
# verify
|
|
10
|
+
alter --version
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
The fastest interactive sign-in is the browser-dance flow — `alter auth login` opens the dashboard, you click **Authorize**, and the CLI receives the freshly-minted token on a localhost listener:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
alter auth login
|
|
19
|
+
# alter: opening browser at https://dashboard.alterauth.com/cli-auth
|
|
20
|
+
# (waiting up to 2 minutes for you to approve)…
|
|
21
|
+
# alter: signed in via browser-dance flow.
|
|
22
|
+
|
|
23
|
+
alter auth status
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
For headless / CI environments, mint a PAT manually from the dashboard (**Settings → Personal Access Tokens → New token**) and feed it to the CLI through one of the channels below:
|
|
27
|
+
|
|
28
|
+
**Token file (recommended for local headless use):** keeps the value out of `process.argv` (visible to other users via `ps`) and out of shell history.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
umask 077 && echo "alter_pat_xxxxxxxxxxxxxxxxxxxxxxxx_yyyyyy" > ~/alter-pat.txt
|
|
32
|
+
alter auth login --token-file ~/alter-pat.txt
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Stdin:**
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pbpaste | alter auth login --token-stdin # macOS
|
|
39
|
+
xclip -o -selection clipboard | alter auth login --token-stdin # Linux
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Env var (CI):** skip persistence entirely. The SDK reads `ALTER_PAT` directly; it never lands in argv.
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
export ALTER_PAT="alter_pat_xxxxxxxxxxxxxxxxxxxxxxxx_yyyyyy"
|
|
46
|
+
alter apps list
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Inline `--token <pat>` is supported but discouraged** — the value lands in `process.argv` (visible to other local users via `ps aux`) and shell history. Use only on single-user machines and rotate afterwards.
|
|
50
|
+
|
|
51
|
+
## Commands
|
|
52
|
+
|
|
53
|
+
The CLI mirrors the dashboard's resource model. Every namespace lives at `alter <namespace> <verb>`:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
auth login | status | logout Sign in / out + token introspection
|
|
57
|
+
apps list | create | show | update | delete Manage applications
|
|
58
|
+
keys list | mint | show | rotate | revoke | rename Manage runtime API keys
|
|
59
|
+
agents list | create | show | update | revoke Managed-agent identities (+ mint-key, list-keys, revoke-key)
|
|
60
|
+
providers list | list-catalog | create | show | update | delete OAuth provider integrations per app
|
|
61
|
+
managed-secrets
|
|
62
|
+
templates | list | show | create | delete | rotate | access | users |
|
|
63
|
+
grants {list, list-for-agent, create, update, revoke} |
|
|
64
|
+
groups {list, show} Managed-secret credentials, grants, and access (CRUD + autocomplete helpers)
|
|
65
|
+
policy show-app View app-level policy (org-wide policy is dashboard-only)
|
|
66
|
+
audit list | show | portal-actions | grant-events | traces Dev-portal audit log
|
|
67
|
+
pats whoami Same as `auth status`, under the `pats` namespace
|
|
68
|
+
link <app-id> | --status Pin an app to the current directory tree
|
|
69
|
+
unlink Clear the workspace pin
|
|
70
|
+
completion install | print Generate shell completions (bash/zsh/fish)
|
|
71
|
+
self-update --to <v> | --dry-run Upgrade the CLI via npm
|
|
72
|
+
sdk-passthrough request <method> <path> [...] Raw authenticated request (escape hatch for routes the CLI doesn't model)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
PAT lifecycle (mint, revoke) remains **dashboard-only** in v1 — a PAT cannot mint or revoke another PAT, including its own. Operators use the dashboard for those actions. Org-wide policy and identity-provider configuration are also dashboard-only per the destructive-action policy in CLAUDE.md.
|
|
76
|
+
|
|
77
|
+
Every list / show command accepts `--output=json|table|jsonl` (default: `json` for pipelines, `table` for interactive). Object commands default to `json`. Use `--fields a,b,c` at the top level to project to specific keys (see [Field selection](#field-selection---fields)).
|
|
78
|
+
|
|
79
|
+
## Authentication
|
|
80
|
+
|
|
81
|
+
The CLI resolves credentials in this order (highest precedence first):
|
|
82
|
+
|
|
83
|
+
1. **`ALTER_PAT` environment variable** — canonical CI / headless source.
|
|
84
|
+
2. **OS keychain** (macOS Keychain, Linux Secret Service / `gnome-keyring`, Windows Credential Manager) via the optional `keytar` native module. This is the default location after a successful `alter auth login`.
|
|
85
|
+
3. **Plaintext file** `~/.config/alter/auth.toml` (XDG-compliant, mode `0600`). Used as the fallback when `keytar` failed to build on the host (e.g. missing `libsecret-1-dev` on Linux). The CLI prints a warning at login time when it falls back to this path.
|
|
86
|
+
|
|
87
|
+
The `--base-url` flag and the `ALTER_BASE_URL` environment variable both require an `https://` URL — non-HTTPS schemes (`http`, `file`, `gopher`, etc.) are rejected at login time so a misconfigured backend URL cannot exfiltrate the PAT in clear text or to an unintended target.
|
|
88
|
+
|
|
89
|
+
If keytar isn't loading on your host, install the native build tools and re-install:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# macOS
|
|
93
|
+
xcode-select --install
|
|
94
|
+
# Linux (Debian/Ubuntu — adjust for your distro)
|
|
95
|
+
sudo apt install libsecret-1-dev gnome-keyring
|
|
96
|
+
# Windows — install windows-build-tools or VS Build Tools
|
|
97
|
+
|
|
98
|
+
npm install -g @alter-ai/cli
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Workspace config (`alter link`)
|
|
102
|
+
|
|
103
|
+
If you work primarily on one app, run `alter link <app-id>` once in the project root. The CLI writes a tiny `.alter/config.yaml` that pins the default app for every subsequent `alter keys`, `alter agents`, `alter providers`, and `alter policy show-app` invocation in that directory tree. No more retyping the UUID.
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
cd ~/code/my-product
|
|
107
|
+
alter link app_abc123
|
|
108
|
+
# alter: pinned app_id=app_abc123 in /Users/me/code/my-product/.alter/config.yaml
|
|
109
|
+
# alter: appended `.alter/` to .gitignore so the pin isn't committed.
|
|
110
|
+
|
|
111
|
+
# from anywhere in this tree, --app becomes optional:
|
|
112
|
+
alter keys list
|
|
113
|
+
alter agents create --name worker --type service
|
|
114
|
+
alter policy show-app
|
|
115
|
+
|
|
116
|
+
# show the current pin
|
|
117
|
+
alter link --status
|
|
118
|
+
|
|
119
|
+
# clear the pin
|
|
120
|
+
alter unlink
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`app_id` precedence (highest first):
|
|
124
|
+
|
|
125
|
+
1. `--app <id>` on the command line
|
|
126
|
+
2. `ALTER_APP_ID` env var
|
|
127
|
+
3. The nearest `.alter/config.yaml` found by walking up from `process.cwd()`
|
|
128
|
+
4. Error: `no app selected` (exit code 2)
|
|
129
|
+
|
|
130
|
+
Discovery walks up the directory tree until it finds an `.alter/` directory OR crosses your home directory (whichever comes first). The home-dir bound prevents a misplaced config in `$HOME` from silently pinning every shell.
|
|
131
|
+
|
|
132
|
+
If your project lives in a git repo, `alter link` appends `.alter/` to `.gitignore` so the workspace pin doesn't get committed — same posture as `vercel link`. The pin is personal-to-the-checkout.
|
|
133
|
+
|
|
134
|
+
## Field selection (`--fields`)
|
|
135
|
+
|
|
136
|
+
Narrow the JSON / JSONL output to specific top-level keys with `--fields a,b,c` at the top level — useful for scripts that only need one or two columns. Inert when paired with `--output=table` (the table columns are already a pre-defined slice). Missing fields render as `null` to keep the column visible.
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# List apps, keep only id + name
|
|
140
|
+
alter apps list --fields id,name
|
|
141
|
+
# [
|
|
142
|
+
# { "id": "app_abc", "name": "demo" },
|
|
143
|
+
# ...
|
|
144
|
+
# ]
|
|
145
|
+
|
|
146
|
+
# Single object — same projection rule
|
|
147
|
+
alter apps show app_abc --fields id,name,environment
|
|
148
|
+
|
|
149
|
+
# JSONL — one projected object per line
|
|
150
|
+
alter audit list --fields timestamp,action --output=jsonl
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The `--fields` value is `,`-separated. Spaces around commas are ignored; spaces INSIDE a field name are rejected up front (catches the common `--fields 'id name'` typo with a clear error rather than silently dropping the second name).
|
|
154
|
+
|
|
155
|
+
## Exit codes
|
|
156
|
+
|
|
157
|
+
`alter` returns a structured exit code so scripts can branch on the failure mode without parsing stderr text. Codes are stable contract — operators can rely on them across releases.
|
|
158
|
+
|
|
159
|
+
| Code | Name | Meaning |
|
|
160
|
+
|------|------------------|-----------------------------------------------------------------------------------------------|
|
|
161
|
+
| 0 | OK | Command succeeded. |
|
|
162
|
+
| 1 | ERROR | Generic runtime failure (uncategorized — including unknown SDK / network errors). |
|
|
163
|
+
| 2 | USAGE | Bad flag, arg, or input format. Always paired with a stderr line naming the offending input. |
|
|
164
|
+
| 3 | AUTH | Not signed in, or PAT revoked / expired. **Remediation:** re-run `alter auth login`. |
|
|
165
|
+
| 4 | NOT_FOUND | Resource not found — 404 from the backend, or a referenced local file is missing. |
|
|
166
|
+
| 5 | CONFLICT | 409 from the backend — most commonly a type-to-confirm mismatch or dependent-resource block. |
|
|
167
|
+
| 6 | RATE_LIMIT | 429 from the backend — retry with backoff. |
|
|
168
|
+
| 7 | FORBIDDEN | 403 from the backend — PAT is valid but lacks the required scope. **Remediation:** re-mint the PAT with broader scopes (or switch PATs); `alter auth login` alone does NOT help. |
|
|
169
|
+
| 8 | CANCELLED | Operator declined an interactive prompt (type-to-confirm mismatch on a destructive action, "no" at a y/N gate). Distinct from `ERROR` (1) — the CLI did nothing wrong, the operator chose not to proceed. Pass `--yes` or `--confirm <name>` in CI to skip the prompt. |
|
|
170
|
+
|
|
171
|
+
Example:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
# Probe whether an app exists without erroring on the not-found case.
|
|
175
|
+
# Capture $? into a local variable BEFORE running anything else; ``$?``
|
|
176
|
+
# is clobbered by every command, so a stray ``log_attempt`` between the
|
|
177
|
+
# ``if`` and ``elif`` would silently break the not-found branch.
|
|
178
|
+
alter apps show "$APP_ID" --output=json > /dev/null 2>&1
|
|
179
|
+
status=$?
|
|
180
|
+
if [ "$status" -eq 0 ]; then
|
|
181
|
+
echo "app exists"
|
|
182
|
+
elif [ "$status" -eq 4 ]; then
|
|
183
|
+
echo "app not found"
|
|
184
|
+
elif [ "$status" -eq 7 ]; then
|
|
185
|
+
echo "PAT lacks dashboard_apps:read — re-mint with broader scopes"
|
|
186
|
+
else
|
|
187
|
+
echo "unexpected error" && exit 1
|
|
188
|
+
fi
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Backend-thrown errors flow through `withClient` and get mapped from HTTP status to exit code automatically (401 → 3, 403 → 7, 404 → 4, 409 → 5, 429 → 6, everything else → 1). Validation errors raised by the CLI itself (e.g. malformed `--limit`) exit 2.
|
|
192
|
+
|
|
193
|
+
## Scope
|
|
194
|
+
|
|
195
|
+
This CLI ships the full dev-portal command surface — `auth`, `apps`, `keys`, `agents`, `providers`, `managed-secrets`, `policy` (read-only at the app level), `audit`, `pats`, `link` / `unlink`, `completion`, `self-update`, and `sdk-passthrough` as a typed-route escape hatch. Backend routes are PAT-callable via `dashboard_*` scopes (see the [scope catalog](https://docs.alterauth.com/api-reference/scopes) for the full list).
|
|
196
|
+
|
|
197
|
+
**Managed secrets — destructive verb tier:** `alter managed-secrets delete <secret-id>` cascade-revokes every grant and delegation tied to the secret, removes the stored credential from secret storage, and writes cascade audit log entries — irrecoverable. The route is gated by `dashboard_secrets:delete` (NOT bundled into `:write` or `:admin`) AND requires `?confirm=<slug>` matching the target secret's slug. The CLI prompts interactively when stdin is a TTY; CI must pass `--confirm <slug>` explicitly. Mirrors `alter apps delete`. Soft-delete operations on grants (`grants revoke`) use the recoverable `:write` tier.
|
|
198
|
+
|
|
199
|
+
**Managed secrets — credential intake:** `create` and `rotate` accept the credential value through three channels, in decreasing safety order: `--credential-value -` reads one line from stdin (preferred for CI piping), `--credential-value @/path/to/file` reads from a file, and `--credential-value <value>` accepts the value inline with a stderr warning about shell-history leakage. Multi-field templates (those whose backend Pydantic model requires more than a single primary credential string) take `--credentials @file.json` (a JSON object of string fields, takes precedence) or repeated `--credential-field key=value` flags.
|
|
200
|
+
|
|
201
|
+
**Dashboard-only operations** (intentional, not scope gaps):
|
|
202
|
+
|
|
203
|
+
- PAT mint / revoke — a PAT cannot manage another PAT, including its own.
|
|
204
|
+
- Org-wide key policy (`/organizations/current/key-policy`) — reading the response body is a security-posture fingerprint, so the route refuses PAT auth on both reads and writes.
|
|
205
|
+
- Identity-provider configuration — affects every grant in the org; never settable by a single scripted call.
|
|
206
|
+
- App-level policy *writes* / *deletes* — only `policy show-app` is exposed by the CLI; mutations remain dashboard-only until a CLI use case emerges.
|
|
207
|
+
|
|
208
|
+
When the CLI doesn't model a route you need, drop down to `alter sdk-passthrough request <METHOD> <path>` — it forwards the request with the current PAT and prints the raw JSON.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `alter` — Alter Vault command-line interface.
|
|
3
|
+
*
|
|
4
|
+
* v1 surface:
|
|
5
|
+
* alter auth login [--token <pat> | --token-file | --token-stdin]
|
|
6
|
+
* Browser-dance OR explicit-token sign-in
|
|
7
|
+
* alter auth status Show the currently-active PAT
|
|
8
|
+
* alter auth logout Forget the locally-stored PAT
|
|
9
|
+
*
|
|
10
|
+
* alter apps list / create / show / update / delete
|
|
11
|
+
* alter keys list / mint / show / rotate / revoke / rename
|
|
12
|
+
* alter agents list / create / show / update / revoke +
|
|
13
|
+
* mint-key / list-keys / revoke-key
|
|
14
|
+
* alter providers list / create / show / update / delete
|
|
15
|
+
* alter managed-secrets
|
|
16
|
+
* templates / list / show / create / delete /
|
|
17
|
+
* rotate / access / users +
|
|
18
|
+
* grants {list, list-for-agent, create, update, revoke} +
|
|
19
|
+
* groups {list, show}
|
|
20
|
+
* alter policy show / show-app (read-only; updates dashboard-only)
|
|
21
|
+
* alter audit list / show / portal-actions / grant-events / traces
|
|
22
|
+
*
|
|
23
|
+
* alter pats whoami Same as `auth status`, under the pats namespace
|
|
24
|
+
*
|
|
25
|
+
* alter completion install [--shell ...] Generate shell completion
|
|
26
|
+
* alter sdk-passthrough request <grant> Runtime SDK escape hatch
|
|
27
|
+
* alter self-update Upgrade the CLI via npm
|
|
28
|
+
*
|
|
29
|
+
* Commands intentionally NOT in the CLI (per CLAUDE.md
|
|
30
|
+
* Destructive-Action Policy):
|
|
31
|
+
* - alter policy update Org-wide config edits are
|
|
32
|
+
* dashboard-only (one CLI call
|
|
33
|
+
* cannot weaken security org-wide).
|
|
34
|
+
* - alter org delete / alter org transfer Org-level destructive ops
|
|
35
|
+
* are dashboard-only.
|
|
36
|
+
*
|
|
37
|
+
* Auth resolution order: ALTER_PAT env var → OS keychain (keytar) →
|
|
38
|
+
* ~/.config/alter/auth.toml plaintext fallback (with first-use warning).
|
|
39
|
+
*
|
|
40
|
+
* Distribution: shipped as `@alter-ai/cli`, binary name `alter`. Single-
|
|
41
|
+
* file bundle via `tsup`; the bundled `dist/cli.js` carries an
|
|
42
|
+
* executable shebang via the build script.
|
|
43
|
+
*/
|
|
44
|
+
/**
|
|
45
|
+
* Rewrite the legacy ``self-update --version <X>`` invocation to use the
|
|
46
|
+
* canonical ``--to <X>`` flag, emitting a deprecation warning to stderr.
|
|
47
|
+
*
|
|
48
|
+
* Background: the subcommand option used to be called ``--version`` but
|
|
49
|
+
* collided with Commander's program-wide ``-V/--version`` flag. The
|
|
50
|
+
* collision meant ``self-update --version 0.2.0`` (space form) was
|
|
51
|
+
* consumed by the global flag, printed the CLI version, and exited 0 —
|
|
52
|
+
* the operator's requested install never happened. QA test ID SU006 +
|
|
53
|
+
* the /review Pass 0 Scenario D follow-up.
|
|
54
|
+
*
|
|
55
|
+
* The rename to ``--to`` fixed the canonical surface, but operators
|
|
56
|
+
* with muscle memory from the old flag still hit the silent-exit-0
|
|
57
|
+
* footgun. This pre-parser runs BEFORE Commander sees argv: if the
|
|
58
|
+
* legacy pattern matches, the flag is rewritten in-place to ``--to`` so
|
|
59
|
+
* Commander dispatches into the subcommand's validator path. A
|
|
60
|
+
* deprecation note is written to stderr so the operator knows to
|
|
61
|
+
* update their scripts.
|
|
62
|
+
*
|
|
63
|
+
* Scope: this pre-parser ONLY touches argv when the ``self-update``
|
|
64
|
+
* subcommand is present. Every other subcommand sees argv verbatim.
|
|
65
|
+
* The rewrite handles both ``--version <value>`` (space form) and
|
|
66
|
+
* ``--version=<value>`` (equals form). A bare ``--version`` without a
|
|
67
|
+
* follow-up value is LEFT ALONE — that's the legitimate "print CLI
|
|
68
|
+
* version" invocation, and rewriting it to ``--to`` (which requires a
|
|
69
|
+
* value) would surface a confusing error.
|
|
70
|
+
*
|
|
71
|
+
* Returns the (possibly rewritten) argv array. Pure function modulo
|
|
72
|
+
* the stderr write on rewrite; safe to call on every CLI startup.
|
|
73
|
+
*/
|
|
74
|
+
declare function rewriteLegacySelfUpdateVersionFlag(argv: string[]): string[];
|
|
75
|
+
|
|
76
|
+
export { rewriteLegacySelfUpdateVersionFlag };
|