@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.
Files changed (4) hide show
  1. package/README.md +208 -0
  2. package/dist/cli.d.ts +76 -0
  3. package/dist/cli.js +12466 -0
  4. 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 };