@zitadel/cli 1.0.0-alpha.21 → 1.0.0-alpha.23

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 (64) hide show
  1. package/README.md +2248 -227
  2. package/SKILLS.md +246 -58
  3. package/dist/groups-CMB0fMzE.mjs +22 -0
  4. package/dist/groups-CMB0fMzE.mjs.map +1 -0
  5. package/dist/index.mjs +16027 -0
  6. package/dist/index.mjs.map +1 -0
  7. package/dist/lib/oclif/help.mjs +67 -0
  8. package/dist/lib/oclif/help.mjs.map +1 -0
  9. package/oclif.manifest.json +4577 -185
  10. package/package.json +42 -8
  11. package/dist/branding-cygSBPkV.mjs +0 -79
  12. package/dist/branding-cygSBPkV.mjs.map +0 -1
  13. package/dist/claim-state-DlfD6Res.mjs +0 -66
  14. package/dist/claim-state-DlfD6Res.mjs.map +0 -1
  15. package/dist/commands/apply.mjs +0 -81
  16. package/dist/commands/apply.mjs.map +0 -1
  17. package/dist/commands/branding/eject.mjs +0 -104
  18. package/dist/commands/branding/eject.mjs.map +0 -1
  19. package/dist/commands/claim.mjs +0 -415
  20. package/dist/commands/claim.mjs.map +0 -1
  21. package/dist/commands/doctor.mjs +0 -1122
  22. package/dist/commands/doctor.mjs.map +0 -1
  23. package/dist/commands/eject.mjs +0 -157
  24. package/dist/commands/eject.mjs.map +0 -1
  25. package/dist/commands/logs.mjs +0 -58
  26. package/dist/commands/logs.mjs.map +0 -1
  27. package/dist/commands/plan.mjs +0 -65
  28. package/dist/commands/plan.mjs.map +0 -1
  29. package/dist/commands/reset.mjs +0 -79
  30. package/dist/commands/reset.mjs.map +0 -1
  31. package/dist/commands/schemas/list.mjs +0 -146
  32. package/dist/commands/schemas/list.mjs.map +0 -1
  33. package/dist/commands/setup.mjs +0 -1271
  34. package/dist/commands/setup.mjs.map +0 -1
  35. package/dist/commands/start.mjs +0 -288
  36. package/dist/commands/start.mjs.map +0 -1
  37. package/dist/commands/status.mjs +0 -151
  38. package/dist/commands/status.mjs.map +0 -1
  39. package/dist/commands/stop.mjs +0 -105
  40. package/dist/commands/stop.mjs.map +0 -1
  41. package/dist/designs-Ckz18Dpo.mjs +0 -38
  42. package/dist/designs-Ckz18Dpo.mjs.map +0 -1
  43. package/dist/docker-Ev1Ggt9l.mjs +0 -436
  44. package/dist/docker-Ev1Ggt9l.mjs.map +0 -1
  45. package/dist/environment-rjRVkJjW.mjs +0 -17
  46. package/dist/environment-rjRVkJjW.mjs.map +0 -1
  47. package/dist/journey-guidance-BGrOX_gT.mjs +0 -40
  48. package/dist/journey-guidance-BGrOX_gT.mjs.map +0 -1
  49. package/dist/oclif-CanO3zdt.mjs +0 -1769
  50. package/dist/oclif-CanO3zdt.mjs.map +0 -1
  51. package/dist/orca-66vAxeIe.mjs +0 -3917
  52. package/dist/orca-66vAxeIe.mjs.map +0 -1
  53. package/dist/package-manager-DFdLcDx1.mjs +0 -194
  54. package/dist/package-manager-DFdLcDx1.mjs.map +0 -1
  55. package/dist/ports-BM20XIZb.mjs +0 -116
  56. package/dist/ports-BM20XIZb.mjs.map +0 -1
  57. package/dist/processes-DKHPkU8O.mjs +0 -120
  58. package/dist/processes-DKHPkU8O.mjs.map +0 -1
  59. package/dist/project-CHhot85s.mjs +0 -140
  60. package/dist/project-CHhot85s.mjs.map +0 -1
  61. package/dist/sync-BBlACKzT.mjs +0 -1633
  62. package/dist/sync-BBlACKzT.mjs.map +0 -1
  63. package/dist/user-schema-DTuOsdKE.mjs +0 -91
  64. package/dist/user-schema-DTuOsdKE.mjs.map +0 -1
package/SKILLS.md CHANGED
@@ -23,7 +23,8 @@ parse the result rather than scraping human output.
23
23
  - The CLI sends anonymous usage telemetry by default. For automated/agent runs
24
24
  that should stay silent, disable it with `--no-telemetry` (per invocation) or
25
25
  `ZITADEL_TELEMETRY=0` / `DO_NOT_TRACK=1` (per environment); this also skips the
26
- small end-of-command network flush.
26
+ small end-of-command network flush and drops the `ci/` and `host/` tokens from
27
+ the CLI's HTTP `User-Agent`.
27
28
  - See `README.md` (its commands section is generated from the CLI's own
28
29
  metadata) or run `zitadel <command> --help` for the full per-command flag list.
29
30
 
@@ -71,6 +72,29 @@ Each invocation prints one JSON object:
71
72
  Stop that process, run `npx @zitadel/cli@alpha stop --all` for host-wide
72
73
  CLI-managed local runtimes, or choose another `start --port`.
73
74
 
75
+ In human mode the output follows the terminal: a TTY gets the project and
76
+ server lines and an aligned table, while a piped or redirected run (or
77
+ `--plain`) gets one tab-separated record per line and nothing else. `--json`
78
+ is unaffected and remains the contract for agents.
79
+
80
+ Text the server returns is escaped before it is printed, in `--json` as in
81
+ human mode, so a value someone stored cannot drive the reader's terminal.
82
+ Control, format and bidi characters in `data` values and keys and in an
83
+ error's `message` appear as visible `\xNN`, `\uNNNN` or `\u{NNNNN}` text;
84
+ newlines and tabs are kept, and a key's backslashes are doubled so two keys
85
+ never merge. A value that contained such a character is therefore not the
86
+ stored value byte for byte: do not send it back in an update as if it were.
87
+ When you need the exact stored value, call the platform API directly with the
88
+ project secret; the CLI only ever shows the escaped form.
89
+ `plan`, `apply` and `setup` are the exception for `.zitadel/` files: they
90
+ write the server's bodies back verbatim and escape only what they print.
91
+
92
+ A property whose name reads as a credential (`password`, `client_secret`,
93
+ `api_key`, …) is refused anywhere on the command line — as an `--attributes`
94
+ entry and inside an inline `--data` body alike, since argv is visible to other
95
+ processes and kept in shell history. Send such bodies with `--file <path>` or
96
+ `--file -` (stdin), which never pass through argv.
97
+
74
98
  Capture stdout and stderr separately when scripting. Some terminals and agent
75
99
  UIs display both streams together, but the machine contract is one parseable
76
100
  JSON object on stdout; installer, audit, and package-manager progress belongs
@@ -80,8 +104,86 @@ Exit codes mirror the error class (3 = validation, 4 = network or not-found,
80
104
  5 = conflict, 1 = auth, 2 = not-implemented). An unknown command is handled by
81
105
  the CLI's help layer, not the envelope.
82
106
 
107
+ ## Resource commands
108
+
109
+ Runtime resources — users, teams, sessions, events, grants, projects — have a
110
+ uniform `zitadel <resource> <verb>` surface built from one registry
111
+ (`src/commands/resources.ts`); the conventions are documented in
112
+ `docs/design/cli/resource-commands.md`. Config resources (schemas, flows,
113
+ branding) stay on `plan` / `apply`; the resource commands never write them.
114
+
115
+ | Resource | Verbs |
116
+ | ---------- | -------------------------------------- |
117
+ | `users` | list, get, create, update, delete |
118
+ | `teams` | list, get, create, update, deactivate |
119
+ | `sessions` | list, get, revoke |
120
+ | `events` | list, get |
121
+ | `grants` | list, get, create, delete |
122
+ | `projects` | list, get, update |
123
+
124
+ Every verb reads the project credential from `.zitadel/secret` and injects
125
+ `project_id` itself; there is no project flag.
126
+
127
+ `zitadel resources --json` reports the whole surface in one call: every
128
+ resource, its verbs, its `filter_fields` / `sort_fields`, and the fields of its writes,
129
+ reported per verb as `create_fields` and `update_fields` (flag name, kind,
130
+ `required`, and any closed value set), and `delete_outcome`, the property a
131
+ delete's envelope carries beside `id`. Prefer it
132
+ over reading `--help` per command. It contacts no server.
133
+
134
+ - `list` emits `data: { items, count, next_page_token }`, and when a page
135
+ remains, `data.next_commands` carries the exact command for the next page —
136
+ the cursor repeated alongside the same `--limit`, `--sort` and `--filter`,
137
+ since a token is only valid with the query that issued it. Prefer it over
138
+ rebuilding the invocation yourself. One page by default
139
+ (`--limit`, `--page-token`); `--all` drains every page and sets
140
+ `next_page_token` to `null`. Query-backed lists take `--filter
141
+ field=operation:value` (repeatable, AND-combined; the operation defaults to
142
+ `equals`) and `--sort field:asc|desc`; the accepted fields are listed in
143
+ `--help` and an unknown one fails with `E_VALIDATION` before any request.
144
+ `events list` takes its filters as named flags (`--category`, `--actor-id`,
145
+ `--created-after`, …).
146
+ - `--fields id,attributes.email` chooses which columns the human rendering
147
+ shows (dot-paths allowed); an unknown path fails before any request, with the
148
+ available ones in `details.available`; a user's schema-defined `attributes`
149
+ accept any key. `--json` always carries the whole resource regardless.
150
+ - `get <id>` emits the resource as `data`. Its human rendering lays the record
151
+ out field by field on a terminal and prints the whole object when piped;
152
+ `--json` is unchanged either way.
153
+ - `create` / `update <id>` take the body either as one flag per schema field
154
+ (`--name`, `--principal-type`, …; run `<resource> create --help` for the
155
+ list, where required fields are marked `(required)`) or as a whole JSON
156
+ object via `--data '<json>'` / `--file <path>` (`--file -` reads stdin). A
157
+ field flag overrides the same key in `--data`. A user's schema-defined
158
+ `attributes` are set with the repeatable `--attributes`, where `key=value` is
159
+ always a string and `key:=value` parses the value as JSON — use `:=` for a
160
+ field the user schema types as a number, boolean, null, array, or object
161
+ (`--attributes age:=42`), and `=` to keep a numeric-looking identifier a
162
+ string (`--attributes postcode=02139`). A missing
163
+ required field fails with `E_VALIDATION`, naming the flags in `message` and
164
+ listing their wire names in `details.missing`. The body is validated against
165
+ the API schema locally, and the server's resource is emitted as `data`. A create adds
166
+ `data.next_commands` pointing at the matching `get`. `--dry-run` emits
167
+ `{ dry_run: true, verb, topic, body }` without calling the platform.
168
+ - The destructive verb (`delete`, `revoke`, `deactivate`) requires `--force` in non-interactive mode (declared per command, so its help says what it permits)
169
+ (the error's `next_commands` carries the exact retry) and report what the API
170
+ did: `{ id, deleted: true }` for users and grants, `{ id, revoked: true }` for
171
+ sessions, and `{ id, deactivated: true }` for teams, whose DELETE deactivates
172
+ the team and leaves it readable (ADR 024). Read the property that accompanies
173
+ `id` rather than assuming `deleted`.
174
+
175
+ ```sh
176
+ npx @zitadel/cli@alpha users list --filter status=active --sort created_at:desc --non-interactive --json
177
+ npx @zitadel/cli@alpha users create --schema sch_… --attributes email=a@b.c --non-interactive --json
178
+ npx @zitadel/cli@alpha sessions revoke sess_… --force --non-interactive --json
179
+ ```
180
+
83
181
  ## Commands
84
182
 
183
+ The groups below mirror the ones `zitadel --help` prints.
184
+
185
+ ### Project commands
186
+
85
187
  - `setup` — create a Zitadel project and scaffold local auth (routes,
86
188
  middleware, `.zitadel/**`, env templates). Setup writes the versioned local
87
189
  default user schema and login flow into
@@ -144,32 +246,48 @@ the CLI's help layer, not the envelope.
144
246
  `hero_url`, from `.zitadel/branding/branding.json`; `hero` falls back to
145
247
  editable text), and setup warns when a widget-posture app picks `split`
146
248
  or `split-right`.
147
- - `plan` — validate config and preview the sync diff without mutating anything.
148
- - `apply` — validate and upload repo config to the platform.
149
- - `plan` and `apply --dry-run` also emit `data.warnings`: non-blocking
150
- findings as `{path, rule, message}`, the same text the human plan prints as
151
- `# warning:` lines and `apply` prints through stderr. They never fail a run.
152
- Two families exist today: flow-definition rules (`warn/…`, mirrored from the
153
- server's validator) and branding asset reachability. `warn/asset-unreachable`
154
- and `warn/asset-content-type` come from a bounded HEAD probe of
155
- `logo_url` / `hero_url` — a URL that is well-formed but dead passes every
156
- gate and then renders as a 0×0 image with nothing in the console, so the
157
- probe is the only place it can be caught. It is advisory by design: the
158
- machine planning is not necessarily the machine that renders the login page.
159
- The probe only contacts public HTTPS destinations and re-checks every
160
- redirect; loopback/private/internal targets stay inconclusive instead of
161
- turning repo config into a network request from the planning host.
162
- Set `ZITADEL_SKIP_ASSET_PROBE` to turn it off (offline, air-gapped CI, or a
163
- CDN that only resolves from production) and `ZITADEL_ASSET_PROBE_TIMEOUT_MS`
164
- to retune the per-URL budget (default 2500).
165
- - In the human-readable plan, a multi-line field (branding's inlined
166
- `liquid_template`) renders as `(<n> lines, sha256:…)` when it is created or
167
- unchanged, and as a changed-line diff when it moved — not as one escaped
168
- line. Read the file itself for full content.
169
- - `schemas list` — inspect the revision history of a user-schema, filtered by
170
- `--object-type` (e.g. `human-user`). Non-interactive/`--json` prints one row
171
- per revision (newest first); interactive adds a picker that fetches and
172
- pretty-prints the selected revision body.
249
+ - `claim` — claim the project for a team to make it permanent. Mints a
250
+ short-lived link, opens it in a browser, and blocks until the developer
251
+ finishes signing in there, then records `claimed_at` and `team_id` in
252
+ `.zitadel/secret`. Nothing about the project changes: the issuer, users,
253
+ passkeys, and applications keep working, and the project secret is not
254
+ rotated. Re-running once the project belongs to a team is a clean
255
+ `status: "skipped"` with `reason: "already-claimed"`, so agents can retry
256
+ safely. The link is always printed before any browser opens, so a headless
257
+ machine, an SSH session, or `--no-open` needs no special handling — copy it
258
+ and open it anywhere. Links last 10 minutes; once one lapses the command
259
+ exits `E_VALIDATION` and points at a fresh run. Claiming itself is only
260
+ possible within 14 days of project creation: past that the platform answers
261
+ `410 proj.claim_window_expired`, the command exits `E_VALIDATION`, and a
262
+ fresh link does **not** help — only a fresh `setup` yields a claimable
263
+ project (the old one can no longer be claimed; it stays temporary and its
264
+ data may be lost).
265
+ `--dry-run` stops before
266
+ anything is minted and reports `status: "skipped"`, `reason: "dry-run"` —
267
+ there is nothing to preview, because a claim is decided in a browser.
268
+ Flags: `--no-open` (print the link instead of launching a browser),
269
+ `--timeout <seconds>` (stop waiting sooner than the link's own expiry).
270
+ `setup`, `status`, and `doctor` report whether a team is attached, reading
271
+ `claimed_at`/`team_id` from `.zitadel/secret` (no platform call). `status`
272
+ carries `data.project.claim` as
273
+ `{"kind": "detached", "claimable": true, "deadline": "2026-09-18T09:00:00.000Z"}`
274
+ (`claimable` flips to `false` once the locally recorded creation time says
275
+ the 14-day window has passed; the guidance then switches to reconciliation
276
+ wording but the claim command stays in `next_commands`, because the local
277
+ record can be stale and running `claim` answers authoritatively — an
278
+ attached project skips cleanly. `deadline` is omitted when the creation
279
+ time is unknown) or
280
+ `{"kind": "attached", "team_id": "team_01H…", "claimed_at": "2026-08-01T09:00:00.000Z"}`,
281
+ and `doctor` reports a
282
+ `claim` check. A project with no team is only ever a **warning**, never a
283
+ failure — it works exactly like one with a team, so `doctor` still exits 0
284
+ and `--fix` deliberately does nothing (a claim needs a human in a browser).
285
+ `status` and `doctor` stay silent about teams off the cloud: they answer
286
+ offline and cannot know whether a local or self-hosted server hosts a
287
+ platform to claim into. `setup` is online anyway, so against a local server
288
+ it probes the runtime document and nudges only when the server hosts the
289
+ platform plane (`platform.bootstrap_project`), where the claim can actually
290
+ complete.
173
291
  - `doctor` — verify generated app files and local state once `zitadel.json`
174
292
  exists. The `managed-files` check compares the scaffolded app files against
175
293
  the manifest setup recorded in `.zitadel/state.json`: a missing
@@ -200,34 +318,11 @@ the CLI's help layer, not the envelope.
200
318
  and are not compared. The repair — an exact-pin install command for the
201
319
  project's detected package manager — is emitted in `data.next_commands`
202
320
  and quoted in the warning message.
203
- - `claim` — attach the project to a team so it becomes permanent. Mints a
204
- short-lived link, opens it in a browser, and blocks until the developer
205
- finishes signing in there, then records `claimed_at` and `team_id` in
206
- `.zitadel/secret`. Nothing about the project changes: the issuer, users,
207
- passkeys, and applications keep working, and the project secret is not
208
- rotated. Re-running once the project belongs to a team is a clean
209
- `status: "skipped"` with `reason: "already-claimed"`, so agents can retry
210
- safely. The link is always printed before any browser opens, so a headless
211
- machine, an SSH session, or `--no-open` needs no special handling — copy it
212
- and open it anywhere. Links last 10 minutes; once one lapses the command
213
- exits `E_VALIDATION` and points at a fresh run. `--dry-run` stops before
214
- anything is minted and reports `status: "skipped"`, `reason: "dry-run"` —
215
- there is nothing to preview, because a claim is decided in a browser.
216
- Flags: `--no-open` (print the link instead of launching a browser),
217
- `--timeout <seconds>` (stop waiting sooner than the link's own expiry).
218
- `setup`, `status`, and `doctor` report whether a team is attached, reading
219
- `claimed_at`/`team_id` from `.zitadel/secret` (no platform call). `status`
220
- carries `data.project.claim` as `{"kind": "detached"}` or
221
- `{"kind": "attached", "team_id": "team_01H…", "claimed_at": "2026-08-01T09:00:00.000Z"}`,
222
- and `doctor` reports a
223
- `claim` check. A project with no team is only ever a **warning**, never a
224
- failure — it works exactly like one with a team, so `doctor` still exits 0
225
- and `--fix` deliberately does nothing (a claim needs a human in a browser).
226
- All three stay silent about teams when the project's `server` in
227
- `zitadel.json` is local or self-hosted, where there is nothing to attach.
228
- - `status` — summarize the local runtime and project state.
229
321
  - `eject` (alias `uninstall`) — remove managed files and local Zitadel state;
230
322
  requires `--force` when non-interactive.
323
+
324
+ ### Local server commands
325
+
231
326
  - `start` — start the managed local Zitadel server and persist runtime metadata
232
327
  under `.zitadel/local/runtime.json`. The binary runtime defaults to SQLite
233
328
  under `.zitadel/local/nextgen-data/`. Runtime metadata reports the published
@@ -235,11 +330,43 @@ the CLI's help layer, not the envelope.
235
330
  `dev+<short-commit>` source build it launched. That label names the revision
236
331
  the binary was built from, which after a Moon cache hit can be an earlier
237
332
  commit whose server sources are byte-identical. Use `--runtime docker` or
238
- `--image` for the Docker backend.
333
+ `--image` for the Docker backend. The project's env files configure the
334
+ local server: every `NEXTGEN_*` variable in `.env.local` and `.env` (the
335
+ former wins; empty values are skipped) is handed to the runtime through its
336
+ environment only (bare `--env NAME` on Docker), so no value reaches `argv`,
337
+ logs, `runtime.json`, or `--json`. The address, data dir and public base the
338
+ CLI sets itself always win. `data.runtime.env` and `runtime.json` carry
339
+ `injected`, the list of names. A running runtime is not updated in place:
340
+ after changing a value run `stop` then `start`. An unreadable env file fails
341
+ `start` with `E_VALIDATION` before any runtime is stopped. `setup` writes a
342
+ comment saying so at the top of the scaffolded `.env.example` and
343
+ `.env.local`.
344
+ The server boots with the platform project
345
+ and a local admin, so the developer exists on their own server without
346
+ signing up: the admin signs in as `admin@zitadel.localhost`, and a
347
+ generated password is kept in `.zitadel/local/admin.json` (gitignored with
348
+ the rest of `.zitadel/local/`) and never printed. `start` prints a one-time
349
+ console sign-in link and reports it as `data.console.sign_in_url` with
350
+ `data.console.signed_in_as`; if no link can be minted (for example a data
351
+ directory from before the local admin existed), `data.console.error` and
352
+ `data.console.hint` say why, `start` still succeeds, and `zitadel console`
353
+ drops out of `next_commands`. Setting `NEXTGEN_PLATFORM_BOOTSTRAP_PROJECT=false`,
354
+ in the shell or in `.env.local` / `.env`, opts out of both the platform project
355
+ and the local admin, for harnesses that
356
+ want a bare single-project server; `data.console` is then absent.
357
+ - `console` — print (and, interactively, open) a fresh one-time sign-in link
358
+ for the local console as the local admin: `data.sign_in_url`,
359
+ `data.signed_in_as`, `data.browser_opened`. Each link works once; run the
360
+ command again for a new one. The console honours the link only when it is
361
+ served from loopback, since the token signs in whoever opens it. Fails with `E_VALIDATION` when `start` never
362
+ created a local admin in this directory. Flags: `--no-open`.
239
363
  - `stop` — stop the managed runtime while preserving
240
364
  `.zitadel/local/nextgen-data`. Use `stop --all` to sweep all discovered
241
365
  host-wide CLI-managed local runtime processes, including healthy runtimes
242
366
  from other local projects; it does not kill arbitrary `/healthz` listeners.
367
+ - `status` — summarize the local runtime and project state.
368
+ `data.server.runtime.env.injected` repeats the variable names recorded at
369
+ the last `start` (empty for a runtime started before this field existed).
243
370
  - `logs` — print managed runtime logs; `--follow` streams in human mode.
244
371
  - `reset` — stop/remove the managed runtime and delete local runtime data;
245
372
  requires `--force` when non-interactive.
@@ -248,6 +375,63 @@ Alpha releases are fixed product package trains. `npx @zitadel/cli@alpha start`
248
375
  uses the matching `@zitadel/server` package by default. `zitadel start --runtime
249
376
  docker --image <ref>` remains the explicit image override for debugging.
250
377
 
378
+ ### Configuration commands
379
+
380
+ - `plan` — validate config and preview the sync diff without mutating anything.
381
+ - `apply` — validate and upload repo config to the platform.
382
+ - `plan` and `apply --dry-run` also emit `data.warnings`: non-blocking
383
+ findings as `{path, rule, message}`, the same text the human plan prints as
384
+ `# warning:` lines and `apply` prints through stderr. They never fail a run.
385
+ Two families exist today: flow-definition rules (`warn/…`, mirrored from the
386
+ server's validator) and branding asset reachability. `warn/asset-unreachable`
387
+ and `warn/asset-content-type` come from a bounded HEAD probe of
388
+ `logo_url` / `hero_url` — a URL that is well-formed but dead passes every
389
+ gate and then renders as a 0×0 image with nothing in the console, so the
390
+ probe is the only place it can be caught. It is advisory by design: the
391
+ machine planning is not necessarily the machine that renders the login page.
392
+ The probe only contacts public HTTPS destinations and re-checks every
393
+ redirect; loopback/private/internal targets stay inconclusive instead of
394
+ turning repo config into a network request from the planning host.
395
+ Set `ZITADEL_SKIP_ASSET_PROBE` to turn it off (offline, air-gapped CI, or a
396
+ CDN that only resolves from production) and `ZITADEL_ASSET_PROBE_TIMEOUT_MS`
397
+ to retune the per-URL budget (default 2500).
398
+ - In the human-readable plan, a multi-line field (branding's inlined
399
+ `liquid_template`) renders as `(<n> lines, sha256:…)` when it is created or
400
+ unchanged, and as a changed-line diff when it moved — not as one escaped
401
+ line. Read the file itself for full content.
402
+ - `schemas list` — inspect the revision history of a user-schema, filtered by
403
+ `--object-type` (e.g. `human-user`). Non-interactive/`--json` prints one row
404
+ per revision (newest first); interactive adds a picker that fetches and
405
+ pretty-prints the selected revision body.
406
+ - `branding eject` — take ownership of the login template: scaffold
407
+ `.zitadel/branding/` (a `branding.json` descriptor plus the `login.liquid`
408
+ template) from a shipped design, `--design centered|split|split-right|hero|minimal`
409
+ or an interactive picker on a TTY. `plan`/`apply` then publish every edit as
410
+ a new branding revision.
411
+ - `variables list|get|set|delete` — manage the per-environment variables and
412
+ secrets a configuration document references as `${{ NAME }}`. Every command
413
+ addresses one owner: `--environment <name>` (`-e`, alias `--env`) names an
414
+ environment, and `--project-level` names the project level. Owners do not
415
+ inherit from one another — a value set at the project level is **not** seen
416
+ by any environment — so a value a running environment needs must be set on
417
+ that environment, and one needed on several must be set on each. Because of
418
+ that, the owner is never defaulted: with neither flag a person is asked and a
419
+ non-interactive run fails with `E_VALIDATION` naming the project's
420
+ environments, as ADR 035 specifies for `deploy`. `set` takes its value from a
421
+ prompt or from stdin and never from a flag, so a credential never reaches
422
+ `argv`; `--secret` stores it encrypted, after which it can be replaced but
423
+ never read back (`list` reports it as held, and `--json` omits the value key
424
+ entirely). `set --as number|boolean` stores a JSON number or boolean
425
+ instead of a string, so a whole-field `${{ NAME }}` reference resolves to that
426
+ type; it is refused with `--secret`, and an integer too large to store exactly
427
+ is refused rather than rounded. Output follows the resource commands: on a
428
+ pipe, `list` prints tab-separated `name`/`value` rows (a secret's value is
429
+ `(secret)`) and `get` prints the whole record as JSON, which carries no
430
+ `value` key for a secret. There is no `pull` and no bulk import. `set` and
431
+ `delete` honour `--dry-run` and make no change (with no owner flag, a person is still asked,
432
+ which reads the project's environments); `delete` needs `--force` when
433
+ non-interactive.
434
+
251
435
  ## Golden path
252
436
 
253
437
  ```sh
@@ -316,7 +500,7 @@ then re-run `plan` and `apply`. Schema and flow files are synced from
316
500
  `.zitadel/schemas/*.json` and `.zitadel/flows/*.json`. Login templates
317
501
  (branding) are synced from `.zitadel/branding/`: a single `branding.json`
318
502
  descriptor (layout, asset URLs) plus a sibling `login.liquid` LiquidJS
319
- template referenced via `liquid_template_file`. Scaffold them with the
503
+ template referenced as `"liquid_template": { "$file": "./login.liquid" }`. Scaffold them with the
320
504
  `branding eject` command (`--design centered|split|split-right|hero|minimal`,
321
505
  interactive picker on a TTY) or at project creation with
322
506
  `setup --design <name>`, which also publishes revision 1. Branding is
@@ -329,9 +513,13 @@ validator (`E_VALIDATION` lists rule ids such as `no-script-tag` and
329
513
  must be absolute `https://`. Keep exactly one descriptor in
330
514
  `.zitadel/branding/` — extra `*.json` files there fail the scan.
331
515
  Server-provisioned defaults remain a fallback for non-CLI project
332
- creation, but CLI-created projects are authored from local files first. Flow create, read, list,
333
- update, and delete are available, while the server enforces lifecycle rules
334
- such as draft-only edits. Managed files carry a marker comment; `eject` removes only
516
+ creation, but CLI-created projects are authored from local files first. Flows are
517
+ revisioned like branding: an edit plans as a `revise` and `apply` publishes a new
518
+ immutable flow revision; a schema revise re-publishes the flows pinned to it with
519
+ the new `user_schema` in the same run. A login pinned by `flow-name` serves that
520
+ flow's newest revision; an unpinned login serves the newest active unscoped flow
521
+ in the project, whatever its name. Removing a flow file does not retire the
522
+ flow. Managed files carry a marker comment; `eject` removes only
335
523
  files that still carry it, preserving anything the user replaced. For app-local
336
524
  development, `--server local` resolves through `.zitadel/local/runtime.json` and
337
525
  requires a healthy
@@ -0,0 +1,22 @@
1
+ //#region src/lib/oclif/groups.ts
2
+ /**
3
+ * The groups the root help lists commands under, declared in print order: the
4
+ * journey runs from setting up a project, to running the local server, to
5
+ * managing its configuration, to acting on the resources inside it. Every command declares its own group
6
+ * (`static group` on the class) so nothing has to be registered centrally; a
7
+ * command without one lands in the trailing {@link ADDITIONAL_COMMANDS_GROUP}
8
+ * with oclif's own utilities.
9
+ */
10
+ const CommandGroups = {
11
+ project: "Project commands",
12
+ localServer: "Local server commands",
13
+ configuration: "Configuration commands",
14
+ resources: "Resource commands"
15
+ };
16
+ const COMMAND_GROUPS = Object.values(CommandGroups);
17
+ /** Where ungrouped commands (oclif's `autocomplete`, `search`, …) are listed. */
18
+ const ADDITIONAL_COMMANDS_GROUP = "Additional commands";
19
+ //#endregion
20
+ export { COMMAND_GROUPS as n, CommandGroups as r, ADDITIONAL_COMMANDS_GROUP as t };
21
+
22
+ //# sourceMappingURL=groups-CMB0fMzE.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"groups-CMB0fMzE.mjs","names":[],"sources":["../src/lib/oclif/groups.ts"],"sourcesContent":["/**\n * The groups the root help lists commands under, declared in print order: the\n * journey runs from setting up a project, to running the local server, to\n * managing its configuration, to acting on the resources inside it. Every command declares its own group\n * (`static group` on the class) so nothing has to be registered centrally; a\n * command without one lands in the trailing {@link ADDITIONAL_COMMANDS_GROUP}\n * with oclif's own utilities.\n */\nexport const CommandGroups = {\n project: \"Project commands\",\n localServer: \"Local server commands\",\n configuration: \"Configuration commands\",\n resources: \"Resource commands\",\n} as const;\n\nexport type CommandGroup = (typeof CommandGroups)[keyof typeof CommandGroups];\n\nexport const COMMAND_GROUPS: readonly CommandGroup[] = Object.values(CommandGroups);\n\n/** Where ungrouped commands (oclif's `autocomplete`, `search`, …) are listed. */\nexport const ADDITIONAL_COMMANDS_GROUP = \"Additional commands\";\n"],"mappings":";;;;;;;;;AAQA,MAAa,gBAAgB;CAC3B,SAAS;CACT,aAAa;CACb,eAAe;CACf,WAAW;CACZ;AAID,MAAa,iBAA0C,OAAO,OAAO,cAAc;;AAGnF,MAAa,4BAA4B"}