@zitadel/cli 0.1.0-alpha.5 → 0.1.0-alpha.8

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 (36) hide show
  1. package/README.md +15 -12
  2. package/SKILLS.md +48 -19
  3. package/dist/commands/apply.mjs +3 -3
  4. package/dist/commands/doctor.mjs +75 -20
  5. package/dist/commands/doctor.mjs.map +1 -1
  6. package/dist/commands/eject.mjs +3 -3
  7. package/dist/commands/logs.mjs +13 -5
  8. package/dist/commands/logs.mjs.map +1 -1
  9. package/dist/commands/plan.mjs +3 -3
  10. package/dist/commands/reset.mjs +16 -7
  11. package/dist/commands/reset.mjs.map +1 -1
  12. package/dist/commands/setup.mjs +3 -3
  13. package/dist/commands/start.mjs +104 -11
  14. package/dist/commands/start.mjs.map +1 -1
  15. package/dist/commands/status.mjs +26 -7
  16. package/dist/commands/status.mjs.map +1 -1
  17. package/dist/commands/stop.mjs +15 -6
  18. package/dist/commands/stop.mjs.map +1 -1
  19. package/dist/docker-BA78SdC2.mjs +383 -0
  20. package/dist/docker-BA78SdC2.mjs.map +1 -0
  21. package/dist/docker-guidance-BvfpmsDj.mjs +21 -0
  22. package/dist/docker-guidance-BvfpmsDj.mjs.map +1 -0
  23. package/dist/{oclif-2t97lHfY.mjs → oclif-VkCTGIEk.mjs} +49 -14
  24. package/dist/oclif-VkCTGIEk.mjs.map +1 -0
  25. package/dist/{orca-CYqJP4ZJ.mjs → orca-CfKDQRop.mjs} +154 -113
  26. package/dist/orca-CfKDQRop.mjs.map +1 -0
  27. package/dist/{project-IzPVR0Pr.mjs → project-CKAHtHML.mjs} +2 -2
  28. package/dist/{project-IzPVR0Pr.mjs.map → project-CKAHtHML.mjs.map} +1 -1
  29. package/dist/{sync-Df9S8Pio.mjs → sync-B5lqgQO3.mjs} +2 -2
  30. package/dist/{sync-Df9S8Pio.mjs.map → sync-B5lqgQO3.mjs.map} +1 -1
  31. package/oclif.manifest.json +23 -1
  32. package/package.json +8 -42
  33. package/dist/docker--EAWr_WY.mjs +0 -210
  34. package/dist/docker--EAWr_WY.mjs.map +0 -1
  35. package/dist/oclif-2t97lHfY.mjs.map +0 -1
  36. package/dist/orca-CYqJP4ZJ.mjs.map +0 -1
package/README.md CHANGED
@@ -15,8 +15,8 @@ automation when reproducibility matters.
15
15
 
16
16
  ## Requirements
17
17
 
18
- - Node 20+
19
- - Docker for the managed local Zitadel runtime
18
+ - Node 24+
19
+ - Docker only when using the optional Docker runtime backend
20
20
  - A Next.js project, or an empty directory where setup can scaffold one
21
21
 
22
22
  ## Quickstart
@@ -30,11 +30,10 @@ npx @zitadel/cli@alpha setup --server local
30
30
  npm run dev
31
31
  ```
32
32
 
33
- `start` runs a Docker-backed local Zitadel server and stores runtime data
34
- under `.zitadel/local/`. Alpha CLI versions use the matching
35
- `ghcr.io/zitadel/nextgen:<cli-version>` image by default; local/dev builds fall
36
- back to `ghcr.io/zitadel/nextgen:latest`. Override with `--image` or
37
- `ZITADEL_LOCAL_IMAGE` for advanced debugging.
33
+ `start` runs the `@zitadel/server` npm binary by default and stores runtime data
34
+ under `.zitadel/local/`. Remote-server setup can use `--server <url>` without
35
+ starting a local runtime. Use `--runtime docker`, `--image`, or
36
+ `ZITADEL_LOCAL_IMAGE` for advanced Docker backend debugging.
38
37
  `setup --server local` creates a project on that local server, asks which
39
38
  framework to scaffold when the directory is fresh, writes the Next.js app into
40
39
  the current directory, scaffolds `app/login`, `app/register`, `app/profile`, and
@@ -63,12 +62,12 @@ passkey can sign in with either credential.
63
62
 
64
63
  ## Other commands
65
64
 
66
- - `zitadel doctor` — verify the local Docker runtime and generated project files
67
- - `zitadel status` — summarise the local Docker runtime and project
65
+ - `zitadel doctor` — verify the local runtime and generated project files
66
+ - `zitadel status` — summarise the local runtime and project
68
67
  - `zitadel plan` — validate config and preview sync changes without mutation
69
68
  - `zitadel apply` — validate and upload repo config to Zitadel
70
69
  - `zitadel eject` — remove what setup wrote (alias: `zitadel uninstall`)
71
- - `zitadel start|stop|logs|reset` — manage the local Docker runtime
70
+ - `zitadel start|stop|logs|reset` — manage the local runtime
72
71
 
73
72
  ## Reference
74
73
 
@@ -188,7 +187,7 @@ Verify local runtime and project state.
188
187
  ```
189
188
  USAGE
190
189
  $ zitadel doctor [--json] [-c <value>] [-s <value>] [-n] [-f] [--dry-run] [--verbose] [--debug] [--fix]
191
- [--image <value>] [--port <value>]
190
+ [--image <value>] [--port <value>] [--runtime binary|docker]
192
191
 
193
192
  FLAGS
194
193
  -c, --cwd=<value> Project directory to operate on.
@@ -200,6 +199,8 @@ FLAGS
200
199
  --fix Re-apply missing managed files.
201
200
  --image=<value> Container image to check.
202
201
  --port=<value> [default: 8080] Local HTTP port.
202
+ --runtime=<option> Local runtime backend.
203
+ <options: binary|docker>
203
204
  --verbose Verbose logging.
204
205
 
205
206
  GLOBAL FLAGS
@@ -394,7 +395,7 @@ Start a local Zitadel server.
394
395
  ```
395
396
  USAGE
396
397
  $ zitadel start [--json] [-c <value>] [-s <value>] [-n] [-f] [--dry-run] [--verbose] [--debug] [--image
397
- <value>] [--port <value>]
398
+ <value>] [--port <value>] [--runtime binary|docker]
398
399
 
399
400
  FLAGS
400
401
  -c, --cwd=<value> Project directory to operate on.
@@ -405,6 +406,8 @@ FLAGS
405
406
  --dry-run Preview without mutating files or the platform.
406
407
  --image=<value> Container image to run.
407
408
  --port=<value> [default: 8080] Local HTTP port.
409
+ --runtime=<option> Local runtime backend.
410
+ <options: binary|docker>
408
411
  --verbose Verbose logging.
409
412
 
410
413
  GLOBAL FLAGS
package/SKILLS.md CHANGED
@@ -42,7 +42,7 @@ Each invocation prints one JSON object:
42
42
  - On failure: `code` (e.g. `E_VALIDATION`, `E_NETWORK`, `E_CONFLICT`) and
43
43
  `message`.
44
44
  - `next_commands`: the suggested follow-ups. Prefer these over free-text hints.
45
- - `E_LOCAL_SERVER_NOT_RUNNING`: start the local Docker runtime with
45
+ - `E_LOCAL_SERVER_NOT_RUNNING`: start the local runtime with
46
46
  `npx @zitadel/cli@alpha start`, then retry with `--server local`.
47
47
 
48
48
  Exit codes mirror the error class (3 = validation, 4 = network, 5 = conflict,
@@ -65,25 +65,24 @@ layer, not the envelope.
65
65
  - `plan` — validate config and preview the sync diff without mutating anything.
66
66
  - `apply` — validate and upload repo config to the platform.
67
67
  - `doctor` — verify generated app files and local state once `zitadel.json`
68
- exists. Local Docker runtime prerequisites are advisory warnings unless an
69
- existing managed runtime is unhealthy; `--fix` re-applies missing managed
70
- files.
71
- - `status` — summarize the local Docker runtime and project state.
68
+ exists. The default local runtime is the `@zitadel/server` npm binary;
69
+ Docker checks apply only when using `--runtime docker` or `--image`.
70
+ `--fix` re-applies missing managed files.
71
+ - `status` — summarize the local runtime and project state.
72
72
  - `eject` (alias `uninstall`) — remove managed files and local Zitadel state;
73
73
  requires `--force` when non-interactive.
74
- - `start` — start the managed local Zitadel container and persist runtime
75
- metadata under `.zitadel/local/runtime.json`.
76
- - `stop` — stop/remove the managed container while preserving
74
+ - `start` — start the managed local Zitadel server and persist runtime metadata
75
+ under `.zitadel/local/runtime.json`. Use `--runtime docker` or `--image` for
76
+ the Docker backend.
77
+ - `stop` — stop the managed runtime while preserving
77
78
  `.zitadel/local/nextgen-data`.
78
- - `logs` — print managed container logs; `--follow` streams in human mode.
79
- - `reset` — stop/remove the managed container and delete local runtime data;
79
+ - `logs` — print managed runtime logs; `--follow` streams in human mode.
80
+ - `reset` — stop/remove the managed runtime and delete local runtime data;
80
81
  requires `--force` when non-interactive.
81
82
 
82
- Alpha releases are lockstep trains. `npx @zitadel/cli@alpha start` runs the
83
- latest tested alpha server image, and
84
- `npx @zitadel/cli@0.1.0-alpha.N start` runs
85
- `ghcr.io/zitadel/nextgen:0.1.0-alpha.N`. `zitadel start --image <ref>` remains
86
- the explicit image override for debugging.
83
+ Alpha releases are fixed product package trains. `npx @zitadel/cli@alpha start`
84
+ uses the matching `@zitadel/server` package by default. `zitadel start --runtime
85
+ docker --image <ref>` remains the explicit image override for debugging.
87
86
 
88
87
  ## Golden path
89
88
 
@@ -107,10 +106,40 @@ npx @zitadel/cli@0.1.0-alpha.N setup --framework next --server local --non-inter
107
106
  After `setup`, follow `data.next_commands` to start the app. Prove the generated
108
107
  auth flow in a visible browser by registering a unique user, logging out, logging
109
108
  back in with the same email/password, and ending on the signed-in profile page.
110
- Do not treat a rendered login or registration form as completion. If browser DOM
111
- snapshots are sparse, target the component hooks exposed by the generated UI:
112
- `zitadel-field-email-input`, `zitadel-field-password-input`, and
113
- `zitadel-action-submit-button`.
109
+ Do not treat a rendered login or registration form as completion.
110
+
111
+ ### Driving the login UI
112
+
113
+ `<zitadel-login>` and `<zitadel-logout>` are Lit elements with open shadow
114
+ roots. The stable automation hooks live inside nested shadow roots, so a flat
115
+ `document.querySelector('[data-testid="zitadel-field-email-input"]')` will not
116
+ find them. Browser drivers with shadow-DOM-aware locators, such as Playwright,
117
+ can target the hooks directly. Generic DOM-eval drivers should pierce shadow
118
+ roots recursively:
119
+
120
+ ```js
121
+ function deepQuery(sel, root = document) {
122
+ const hit = root.querySelector(sel);
123
+ if (hit) return hit;
124
+ for (const el of root.querySelectorAll("*")) {
125
+ if (el.shadowRoot) {
126
+ const result = deepQuery(sel, el.shadowRoot);
127
+ if (result) return result;
128
+ }
129
+ }
130
+ return null;
131
+ }
132
+ ```
133
+
134
+ Use `zitadel-field-email-input`, `zitadel-field-password-input`, and
135
+ `zitadel-action-submit-button` for sign-in and registration. For sign-out, open
136
+ the user menu button if needed, then pierce to `.signout-btn`; Playwright-style
137
+ locators may use `zitadel-logout .signout-btn`. The canonical component hook
138
+ list lives in `packages/components/README.md`.
139
+
140
+ The checked-in automated regression path is `moon run workspace:journey`, which
141
+ exercises fresh-app setup plus registration, logout, and login across the
142
+ supported frameworks.
114
143
 
115
144
  Repo config is authoritative: edit `zitadel.json` or files under `.zitadel/`,
116
145
  then re-run `plan` and `apply`. Managed files carry a marker comment; `eject`
@@ -1,6 +1,6 @@
1
- import { t as BaseCommand } from "../oclif-2t97lHfY.mjs";
2
- import { o as readZitadelSecret } from "../project-IzPVR0Pr.mjs";
3
- import { a as makeSyncers, i as runSyncLoop, n as summarizePlan, o as environmentSchema, r as buildSyncPlan, t as renderPlan } from "../sync-Df9S8Pio.mjs";
1
+ import { t as BaseCommand } from "../oclif-VkCTGIEk.mjs";
2
+ import { o as readZitadelSecret } from "../project-CKAHtHML.mjs";
3
+ import { a as makeSyncers, i as runSyncLoop, n as summarizePlan, o as environmentSchema, r as buildSyncPlan, t as renderPlan } from "../sync-B5lqgQO3.mjs";
4
4
  import { Flags } from "@oclif/core";
5
5
  import { createZitadelClient } from "@zitadel/api/client";
6
6
  import { consola as consola$1 } from "consola";
@@ -1,7 +1,8 @@
1
- import { D as ZitadelError, a as DEFAULT_LOCAL_SERVER_PORT, c as checkLocalServerHealth, f as isPortAvailable, h as readRuntimeMetadata, l as defaultLocalServerImageForCliVersion, m as localServerUrl, s as assertLocalStateWritable, t as BaseCommand, w as isObject, x as publicCliCommand } from "../oclif-2t97lHfY.mjs";
2
- import { r as issuerFromPort, t as createOrca } from "../orca-CYqJP4ZJ.mjs";
3
- import { a as readZitadelConfig, i as readRendererId, o as readZitadelSecret, r as readDevelopmentIssuer, t as hasZitadelConfig } from "../project-IzPVR0Pr.mjs";
4
- import { o as imageAvailable, r as dockerAvailable } from "../docker--EAWr_WY.mjs";
1
+ import { D as ZitadelError, a as DEFAULT_LOCAL_SERVER_PORT, c as checkLocalServerHealth, f as isPortAvailable, h as readRuntimeMetadata, l as defaultLocalServerImageForCliVersion, m as localServerUrl, s as assertLocalStateWritable, t as BaseCommand, w as isObject, x as publicCliCommand } from "../oclif-VkCTGIEk.mjs";
2
+ import { r as issuerFromPort, t as createOrca } from "../orca-CfKDQRop.mjs";
3
+ import { a as readZitadelConfig, i as readRendererId, o as readZitadelSecret, r as readDevelopmentIssuer, t as hasZitadelConfig } from "../project-CKAHtHML.mjs";
4
+ import { d as assertServerPackageAvailable, o as imageAvailable, r as dockerAvailable } from "../docker-BA78SdC2.mjs";
5
+ import { n as dockerUnavailableMessage, t as dockerRuntimeGuidance } from "../docker-guidance-BvfpmsDj.mjs";
5
6
  import { Flags } from "@oclif/core";
6
7
  import consola from "consola";
7
8
  import { join } from "node:path";
@@ -247,6 +248,7 @@ const SANITY_CHECKS = [
247
248
  //#endregion
248
249
  //#region src/commands/doctor/index.ts
249
250
  const LOCAL_RUNTIME_CHECK_NAMES = new Set([
251
+ "server-binary",
250
252
  "docker-cli",
251
253
  "image",
252
254
  "state-dir",
@@ -274,6 +276,10 @@ var Doctor = class Doctor extends BaseCommand {
274
276
  port: Flags.integer({
275
277
  description: "Local HTTP port.",
276
278
  default: DEFAULT_LOCAL_SERVER_PORT
279
+ }),
280
+ runtime: Flags.string({
281
+ description: "Local runtime backend.",
282
+ options: ["binary", "docker"]
277
283
  })
278
284
  };
279
285
  async run() {
@@ -284,8 +290,15 @@ var Doctor = class Doctor extends BaseCommand {
284
290
  source: localServerUrl(port)
285
291
  });
286
292
  const { cwd, dryRun } = this.meta;
293
+ const existingRuntime = await readRuntimeMetadata(cwd);
294
+ const runtimeBackend = resolveRuntimeBackend({
295
+ runtime: flags.runtime,
296
+ image: flags.image,
297
+ envImage: this.meta.env.ZITADEL_LOCAL_IMAGE,
298
+ existingRuntime
299
+ });
287
300
  const image = flags.image ?? this.meta.env.ZITADEL_LOCAL_IMAGE ?? defaultLocalServerImageForCliVersion(this.meta.cliVersion);
288
- const runtimeChecks = await runLocalRuntimeChecks(cwd, image, port);
301
+ const runtimeChecks = await runLocalRuntimeChecks(cwd, runtimeBackend, image, port);
289
302
  const hasConfig = await hasZitadelConfig(cwd);
290
303
  const ctx = {
291
304
  cwd,
@@ -308,13 +321,19 @@ var Doctor = class Doctor extends BaseCommand {
308
321
  const checks = [...runtimeChecks, ...projectChecks];
309
322
  const failed = checks.filter((check) => check.status === "fail");
310
323
  const warnings = checks.filter((check) => check.status === "warn");
324
+ const warningAdvice = advisoryForWarnings(warnings, this.meta.cliVersion);
311
325
  const data = {
312
326
  title: failed.length > 0 ? "Zitadel doctor found issues." : warnings.length > 0 ? "Zitadel doctor passed with warnings." : "Zitadel doctor passed.",
313
327
  ok: failed.length === 0,
314
- image,
328
+ runtime: runtimeBackend,
329
+ ...runtimeBackend === "docker" ? { image } : {},
315
330
  port,
316
331
  project: { lifecycle: hasConfig ? "configured" : "not-configured" },
317
- checks
332
+ checks,
333
+ ...warningAdvice ? {
334
+ next_actions: warningAdvice.nextActions,
335
+ next_commands: warningAdvice.nextCommands
336
+ } : {}
318
337
  };
319
338
  if (failed.length > 0) {
320
339
  const advice = failureAdvice(failed, image, port, this.meta.cliVersion);
@@ -333,10 +352,17 @@ var Doctor = class Doctor extends BaseCommand {
333
352
  };
334
353
  function failureAdvice(failed, image, port, cliVersion) {
335
354
  const failedNames = new Set(failed.map((check) => check.name));
336
- if (failedNames.has("docker-cli")) return {
337
- hint: "Docker is required for `zitadel start`, but the Docker daemon is not reachable. Install or start Docker, then rerun `zitadel doctor`.",
338
- nextCommands: ["docker version", publicCliCommand("doctor", cliVersion)]
355
+ if (failedNames.has("server-binary")) return {
356
+ hint: "The Zitadel server npm package is not available. Reinstall the CLI package, then retry.",
357
+ nextCommands: [publicCliCommand("doctor", cliVersion)]
339
358
  };
359
+ if (failedNames.has("docker-cli")) {
360
+ const advice = dockerRuntimeGuidance("doctor", cliVersion);
361
+ return {
362
+ hint: advice.hint,
363
+ nextCommands: advice.nextCommands
364
+ };
365
+ }
340
366
  if (failedNames.has("image")) return {
341
367
  hint: "The local Zitadel image is not available. Check Docker registry access, build it locally, or pass --image / ZITADEL_LOCAL_IMAGE.",
342
368
  nextCommands: [`docker pull ${image}`, publicCliCommand("doctor", cliVersion)]
@@ -365,8 +391,31 @@ function failureAdvice(failed, image, port, cliVersion) {
365
391
  nextCommands: [publicCliCommand("doctor", cliVersion)]
366
392
  };
367
393
  }
368
- async function runLocalRuntimeChecks(cwd, image, port) {
394
+ function advisoryForWarnings(warnings, cliVersion) {
395
+ if (!warnings.some((check) => check.name === "docker-cli")) return;
396
+ const advice = dockerRuntimeGuidance("doctor", cliVersion);
397
+ return {
398
+ nextActions: advice.nextActions,
399
+ nextCommands: advice.nextCommands
400
+ };
401
+ }
402
+ async function runLocalRuntimeChecks(cwd, runtimeBackend, image, port) {
369
403
  const runtime = await readRuntimeMetadata(cwd);
404
+ if (runtimeBackend === "binary") return [
405
+ await check("server-binary", "Server npm package is available", async () => {
406
+ return `@zitadel/server ${await assertServerPackageAvailable()} is available`;
407
+ }),
408
+ await check("state-dir", "Local state directory is writable", async () => {
409
+ const probe = await assertLocalStateWritable(cwd);
410
+ return probe.checkedPath === probe.targetPath ? `${probe.targetPath} is writable` : `${probe.targetPath} can be created (${probe.checkedPath} is writable)`;
411
+ }, "warn"),
412
+ await check("port", `Port ${String(port)} is available`, async () => {
413
+ if (runtime && await checkLocalServerHealth(runtime.server_url)) return `${runtime.server_url} is already healthy`;
414
+ if (!await isPortAvailable(port)) throw new Error(`Port ${String(port)} is already in use`);
415
+ return `Port ${String(port)} is available`;
416
+ }, "warn"),
417
+ await checkRuntime(runtime, runtimeBackend)
418
+ ];
370
419
  const docker = await check("docker-cli", "Docker is reachable", async () => {
371
420
  let result;
372
421
  try {
@@ -399,13 +448,23 @@ async function runLocalRuntimeChecks(cwd, image, port) {
399
448
  if (!await isPortAvailable(port)) throw new Error(`Port ${String(port)} is already in use`);
400
449
  return `Port ${String(port)} is available`;
401
450
  }, "warn"),
402
- await check("runtime", "Existing local runtime is healthy", async () => {
403
- if (!runtime) return "No existing runtime metadata";
404
- if (!await checkLocalServerHealth(runtime.server_url)) throw new Error(`${runtime.server_url} did not respond to /healthz`);
405
- return `${runtime.server_url} is healthy`;
406
- })
451
+ await checkRuntime(runtime, runtimeBackend)
407
452
  ];
408
453
  }
454
+ async function checkRuntime(runtime, runtimeBackend) {
455
+ return check("runtime", "Existing local runtime is healthy", async () => {
456
+ if (!runtime) return "No existing runtime metadata";
457
+ if (runtime.backend !== runtimeBackend) throw new Error(`Existing local runtime uses ${runtime.backend}; run start --runtime ${runtimeBackend} to switch backends.`);
458
+ if (!await checkLocalServerHealth(runtime.server_url)) throw new Error(`${runtime.server_url} did not respond to /healthz`);
459
+ return `${runtime.server_url} is healthy`;
460
+ });
461
+ }
462
+ function resolveRuntimeBackend(input) {
463
+ if (input.runtime === "binary" || input.runtime === "docker") return input.runtime;
464
+ if (input.existingRuntime) return input.existingRuntime.backend;
465
+ if (input.image || input.envImage) return "docker";
466
+ return "binary";
467
+ }
409
468
  async function check(name, fallback, run, failureStatus = "fail") {
410
469
  try {
411
470
  return {
@@ -421,10 +480,6 @@ async function check(name, fallback, run, failureStatus = "fail") {
421
480
  };
422
481
  }
423
482
  }
424
- function dockerUnavailableMessage(error) {
425
- const detail = error instanceof Error ? error.message : String(error);
426
- return `Docker is not reachable${detail.trim() ? ` (${detail.trim()})` : ""}; \`zitadel start\` needs Docker, but cloud setup can continue.`;
427
- }
428
483
  function imageUnavailableMessage(image, error) {
429
484
  const detail = error instanceof Error ? error.message : String(error);
430
485
  return `Image ${image} is not available to Docker${detail.trim() ? ` (${detail.trim()})` : ""}; \`zitadel start\` may need a pull or a different image.`;
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.mjs","names":[],"sources":["../../src/commands/doctor/checks/types.ts","../../src/commands/doctor/checks/config.ts","../../src/commands/doctor/checks/secret.ts","../../src/commands/doctor/checks/secret-permissions.ts","../../src/commands/doctor/checks/gitignore.ts","../../src/commands/doctor/checks/env-example.ts","../../src/commands/doctor/checks/framework.ts","../../src/commands/doctor/patch-context.ts","../../src/commands/doctor/checks/dependency.ts","../../src/commands/doctor/checks/project-match.ts","../../src/commands/doctor/checks/index.ts","../../src/commands/doctor/index.ts"],"sourcesContent":["import type { Orca } from \"../../../lib/orca\";\n\n/** Pass/fail/advisory outcome of a single {@link SanityCheck}. */\nexport type CheckOutcome = {\n name: string;\n status: \"pass\" | \"warn\" | \"fail\";\n message: string;\n path?: string;\n};\n\n/** Everything a check needs to inspect or repair a project. */\nexport type CheckContext = {\n readonly cwd: string;\n readonly orca: Orca;\n readonly cliVersion: string;\n /** When true, {@link SanityCheck.fix} must preview without writing. */\n readonly dryRun: boolean;\n};\n\n/**\n * One diagnostic the `doctor` command runs. Each concrete check is a small\n * standalone class that both verifies its concern ({@link run}) and knows how\n * to repair it ({@link fix}); the command executes every registered check,\n * aggregates the {@link CheckOutcome}s, and (under `--fix`) repairs the ones\n * that failed.\n */\nexport interface SanityCheck {\n /** Stable identifier surfaced in logs and the JSON envelope. */\n readonly name: string;\n run(ctx: CheckContext): Promise<CheckOutcome>;\n /** Repair what this check verifies. A no-op when there is no safe auto-fix. */\n fix(ctx: CheckContext): Promise<void>;\n}\n\n/**\n * Base class for checks: subclasses declare `name`, `path`, and a success\n * `summary`, and implement the single {@link verify} method that throws on\n * failure. {@link run} wraps it so a thrown error becomes a `fail` outcome\n * carrying the error message, and success becomes a `pass` with `summary`.\n *\n * {@link fix} defaults to a no-op: checks whose failure has no safe automatic\n * remedy (a missing secret, an invalid user schema) simply do not override it.\n */\nexport abstract class AbstractSanityCheck implements SanityCheck {\n abstract readonly name: string;\n abstract readonly path: string;\n protected abstract readonly summary: string;\n\n /** Throw to signal failure; the thrown message is surfaced to the user. */\n protected abstract verify(ctx: CheckContext): Promise<void>;\n\n async run(ctx: CheckContext): Promise<CheckOutcome> {\n try {\n await this.verify(ctx);\n return { name: this.name, status: \"pass\", message: this.summary, path: this.path };\n } catch (error) {\n return {\n name: this.name,\n status: \"fail\",\n message: error instanceof Error ? error.message : String(error),\n path: this.path,\n };\n }\n }\n\n async fix(_ctx: CheckContext): Promise<void> {\n return;\n }\n}\n","import { readZitadelConfig } from \"../../../lib/project\";\nimport { AbstractSanityCheck, type CheckContext } from \"./types\";\n\n/** Verifies `zitadel.json` exists and parses. */\nexport class ConfigCheck extends AbstractSanityCheck {\n readonly name = \"config\";\n readonly path = \"zitadel.json\";\n protected readonly summary = \"zitadel.json parses\";\n\n protected async verify(ctx: CheckContext): Promise<void> {\n await readZitadelConfig(ctx.cwd);\n }\n}\n","import { readZitadelSecret } from \"../../../lib/project\";\nimport { AbstractSanityCheck, type CheckContext } from \"./types\";\n\n/** Verifies `.zitadel/secret` exists and parses. */\nexport class SecretCheck extends AbstractSanityCheck {\n readonly name = \"secret\";\n readonly path = \".zitadel/secret\";\n protected readonly summary = \".zitadel/secret parses\";\n\n protected async verify(ctx: CheckContext): Promise<void> {\n await readZitadelSecret(ctx.cwd);\n }\n}\n","import { chmod, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { AbstractSanityCheck, type CheckContext } from \"./types\";\n\n/** Verifies `.zitadel/secret` is locked down to `0600`, and re-locks it on fix. */\nexport class SecretPermissionsCheck extends AbstractSanityCheck {\n readonly name = \"secret-permissions\";\n readonly path = \".zitadel/secret\";\n protected readonly summary = \".zitadel/secret has 0600 permissions\";\n\n protected async verify(ctx: CheckContext): Promise<void> {\n const mode = (await stat(join(ctx.cwd, \".zitadel/secret\"))).mode & 0o777;\n if (mode !== 0o600) {\n throw new Error(`expected 0600, got ${mode.toString(8)}`);\n }\n }\n\n override async fix(ctx: CheckContext): Promise<void> {\n if (ctx.dryRun) {\n return;\n }\n await chmod(join(ctx.cwd, \".zitadel/secret\"), 0o600);\n }\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { AbstractSanityCheck, type CheckContext } from \"./types\";\n\n/** The entries `.gitignore` must carry to keep secrets and env files untracked. */\nconst REQUIRED_ENTRIES = [\".zitadel/secret\", \".env*\", \"!.env.example\"];\n\n/** Verifies `.gitignore` excludes the local secret and env files; appends any missing. */\nexport class GitignoreCheck extends AbstractSanityCheck {\n readonly name = \"gitignore\";\n readonly path = \".gitignore\";\n protected readonly summary = \".gitignore protects local secret/env files\";\n\n protected async verify(ctx: CheckContext): Promise<void> {\n const lines = (await readFile(join(ctx.cwd, \".gitignore\"), \"utf8\")).split(/\\r?\\n/g);\n for (const entry of REQUIRED_ENTRIES) {\n if (!lines.includes(entry)) {\n throw new Error(`missing ${entry}`);\n }\n }\n }\n\n override async fix(ctx: CheckContext): Promise<void> {\n const path = join(ctx.cwd, \".gitignore\");\n const existing = await readFile(path, \"utf8\").catch(() => \"\");\n const lines = existing.split(/\\r?\\n/g);\n const missing = REQUIRED_ENTRIES.filter((entry) => !lines.includes(entry));\n if (missing.length === 0 || ctx.dryRun) {\n return;\n }\n const prefix = existing.length > 0 && !existing.endsWith(\"\\n\") ? \"\\n\" : \"\";\n await writeFile(path, `${existing}${prefix}${missing.join(\"\\n\")}\\n`);\n }\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { AbstractSanityCheck, type CheckContext } from \"./types\";\n\n/** The keys `.env.example` must document for a Zitadel-managed project. */\nconst REQUIRED_KEYS = [\"ZITADEL_PROJECT_ID\", \"ZITADEL_ENVIRONMENT\", \"ZITADEL_ISSUER\"];\n\n/** Verifies `.env.example` documents the required Zitadel keys; appends any missing. */\nexport class EnvExampleCheck extends AbstractSanityCheck {\n readonly name = \"env-example\";\n readonly path = \".env.example\";\n protected readonly summary = \".env.example references required keys\";\n\n protected async verify(ctx: CheckContext): Promise<void> {\n const contents = await readFile(join(ctx.cwd, \".env.example\"), \"utf8\");\n for (const key of REQUIRED_KEYS) {\n if (!contents.includes(`${key}=`)) {\n throw new Error(`missing ${key}`);\n }\n }\n }\n\n override async fix(ctx: CheckContext): Promise<void> {\n const path = join(ctx.cwd, \".env.example\");\n const existing = await readFile(path, \"utf8\").catch(() => \"\");\n const missing = REQUIRED_KEYS.filter((key) => !existing.includes(`${key}=`));\n if (missing.length === 0 || ctx.dryRun) {\n return;\n }\n const prefix = existing.length > 0 && !existing.endsWith(\"\\n\") ? \"\\n\" : \"\";\n await writeFile(path, `${existing}${prefix}${missing.map((key) => `${key}=`).join(\"\\n\")}\\n`);\n }\n}\n","import { isObject } from \"../../../lib/json\";\nimport { readZitadelConfig } from \"../../../lib/project\";\nimport { AbstractSanityCheck, type CheckContext } from \"./types\";\n\n/** Verifies the framework detected on disk matches the one recorded in config. */\nexport class FrameworkCheck extends AbstractSanityCheck {\n readonly name = \"framework\";\n readonly path = \"zitadel.json\";\n protected readonly summary = \"Detected framework matches recorded framework\";\n\n protected async verify(ctx: CheckContext): Promise<void> {\n const config = await readZitadelConfig(ctx.cwd);\n const detected = await ctx.orca.detect(ctx.cwd);\n const recorded = isObject(config.framework) ? config.framework.id : undefined;\n if (recorded !== detected.id) {\n throw new Error(`expected ${String(recorded)}, detected ${detected.id}`);\n }\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { issuerFromPort, type FrameworkFacts, type Orca } from \"../../lib/orca\";\nimport type { PatchContext } from \"../../lib/orca/patchers/types\";\nimport { readDevelopmentIssuer, readRendererId, readZitadelConfig, readZitadelSecret } from \"../../lib/project\";\n\n/**\n * Reconstructs a {@link PatchContext} from the on-disk project (config, secret)\n * plus fresh framework detection, so a patcher repair can rebuild its plan.\n * Used by the dependency check's `fix`, which reclaims the framework-specific\n * SDK package via `patcher.repair`. The user schema and flow definition are\n * server-owned and no longer scaffolded locally, so nothing here reads them.\n */\nexport async function loadPatchContext(\n cwd: string,\n orca: Orca,\n cliVersion: string,\n): Promise<PatchContext> {\n const config = await readZitadelConfig(cwd);\n const secret = await readZitadelSecret(cwd);\n const framework = await orca.detect(cwd);\n return {\n framework,\n rendererId: readRendererId(config),\n issuer: await resolveIssuer(cwd, config, framework),\n server: typeof config.server === \"string\" ? config.server : \"\",\n cliVersion,\n project: {\n id: secret.project_id,\n projectSecret: secret.project_secret,\n previewSecret: secret.preview_secret,\n previewOrigins: secret.preview_origins,\n createdAt: secret.created_at,\n },\n };\n}\n\nasync function resolveIssuer(\n cwd: string,\n config: Record<string, unknown>,\n facts: FrameworkFacts,\n): Promise<string> {\n const fromConfig = readDevelopmentIssuer(config);\n if (fromConfig && fromConfig.length > 0) {\n return fromConfig;\n }\n const state = await readState(cwd);\n if (typeof state?.dev_port === \"number\") {\n return issuerFromPort(state.dev_port);\n }\n return facts.url;\n}\n\nasync function readState(cwd: string): Promise<{ dev_port?: number } | undefined> {\n try {\n const contents = await readFile(join(cwd, \".zitadel/state.json\"), \"utf8\");\n return JSON.parse(contents) as { dev_port?: number };\n } catch {\n return undefined;\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { loadPatchContext } from \"../patch-context\";\nimport { AbstractSanityCheck, type CheckContext } from \"./types\";\n\n/**\n * Verifies the project still declares a Zitadel SDK dependency in\n * `package.json`. The patcher adds a scoped package (e.g.\n * `@zitadel/sdk-next`); the check is generic over the `@zitadel*`\n * scope so any framework renderer's dependency satisfies it.\n */\nexport class DependencyCheck extends AbstractSanityCheck {\n readonly name = \"dependency\";\n readonly path = \"package.json\";\n protected readonly summary = \"package.json depends on a Zitadel SDK package\";\n\n protected async verify(ctx: CheckContext): Promise<void> {\n const pkg = JSON.parse(await readFile(join(ctx.cwd, \"package.json\"), \"utf8\")) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const names = [\n ...Object.keys(pkg.dependencies ?? {}),\n ...Object.keys(pkg.devDependencies ?? {}),\n ];\n if (!names.some((name) => name.startsWith(\"@zitadel\"))) {\n throw new Error(\"no @zitadel* dependency found in package.json\");\n }\n }\n\n /**\n * Repairs by reclaiming the patcher's managed artifacts: rebuilds the\n * `PatchContext` from disk and calls `patcher.repair`, which re-adds the\n * SDK dependency via its `add-dep` op. The exact package name is framework\n * + renderer specific and known only to the patcher (which deliberately\n * hides its file-op plan behind the family-neutral `Patcher` interface),\n * so going through `repair` is the only sanctioned path.\n */\n override async fix(ctx: CheckContext): Promise<void> {\n const patchCtx = await loadPatchContext(ctx.cwd, ctx.orca, ctx.cliVersion);\n await ctx.orca.patcherFor(patchCtx.framework.id).repair(patchCtx, {\n cwd: ctx.cwd,\n dryRun: ctx.dryRun,\n force: true,\n });\n }\n}\n","import { readZitadelConfig, readZitadelSecret } from \"../../../lib/project\";\nimport { AbstractSanityCheck, type CheckContext } from \"./types\";\n\n/** Verifies `.zitadel/secret`'s project_id matches `zitadel.json`'s project. */\nexport class ProjectMatchCheck extends AbstractSanityCheck {\n readonly name = \"project-match\";\n readonly path = \".zitadel/secret\";\n protected readonly summary = \".zitadel/secret project_id matches zitadel.json project\";\n\n protected async verify(ctx: CheckContext): Promise<void> {\n const config = await readZitadelConfig(ctx.cwd);\n const secret = await readZitadelSecret(ctx.cwd);\n const configProject = typeof config.project === \"string\" ? config.project : undefined;\n if (secret.project_id !== configProject) {\n throw new Error(\".zitadel/secret project_id does not match zitadel.json project\");\n }\n }\n}\n","/**\n * Public surface for the doctor sanity checks. The `doctor` command imports\n * {@link SANITY_CHECKS} and runs every entry, aggregating the outcomes. Each\n * check is a small standalone class (see its own file); add a new diagnostic\n * by writing a class and appending an instance to the registry below.\n */\nimport type { SanityCheck } from \"./types\";\nimport { ConfigCheck } from \"./config\";\nimport { SecretCheck } from \"./secret\";\nimport { SecretPermissionsCheck } from \"./secret-permissions\";\nimport { GitignoreCheck } from \"./gitignore\";\nimport { EnvExampleCheck } from \"./env-example\";\nimport { FrameworkCheck } from \"./framework\";\nimport { DependencyCheck } from \"./dependency\";\nimport { ProjectMatchCheck } from \"./project-match\";\n\nexport type { SanityCheck, CheckContext, CheckOutcome } from \"./types\";\nexport { AbstractSanityCheck } from \"./types\";\nexport { ConfigCheck } from \"./config\";\nexport { SecretCheck } from \"./secret\";\nexport { SecretPermissionsCheck } from \"./secret-permissions\";\nexport { GitignoreCheck } from \"./gitignore\";\nexport { EnvExampleCheck } from \"./env-example\";\nexport { FrameworkCheck } from \"./framework\";\nexport { SchemaCheck } from \"./schema\";\nexport { DependencyCheck } from \"./dependency\";\nexport { ProjectMatchCheck } from \"./project-match\";\n\n/** Every diagnostic the `doctor` command runs, in display order. */\nexport const SANITY_CHECKS: ReadonlyArray<SanityCheck> = [\n new ConfigCheck(),\n new SecretCheck(),\n new SecretPermissionsCheck(),\n new GitignoreCheck(),\n new EnvExampleCheck(),\n new FrameworkCheck(),\n // SchemaCheck is disabled: the user schema is now provisioned server-side\n // and no longer scaffolded into `.zitadel/schemas/user.json`, so there is\n // no local file to verify. The check is kept (imported/exported below) for\n // the future pull-based workflow that will re-introduce local resources.\n // new SchemaCheck(),\n new DependencyCheck(),\n new ProjectMatchCheck(),\n];\n","import { Flags } from \"@oclif/core\";\nimport consola from \"consola\";\n\nimport { ZitadelError } from \"../../lib/errors\";\nimport { dockerAvailable, imageAvailable } from \"../../lib/local-server/docker\";\nimport {\n DEFAULT_LOCAL_SERVER_PORT,\n assertLocalStateWritable,\n checkLocalServerHealth,\n defaultLocalServerImageForCliVersion,\n isPortAvailable,\n localServerUrl,\n readRuntimeMetadata,\n} from \"../../lib/local-server/runtime\";\nimport { BaseCommand, type JsonEnvelope } from \"../../lib/oclif\";\nimport { createOrca } from \"../../lib/orca\";\nimport { hasZitadelConfig } from \"../../lib/project\";\nimport { publicCliCommand } from \"../../lib/public-cli\";\nimport { SANITY_CHECKS, type CheckContext, type CheckOutcome } from \"./checks\";\n\nconst LOCAL_RUNTIME_CHECK_NAMES = new Set([\"docker-cli\", \"image\", \"state-dir\", \"port\", \"runtime\"]);\n\n/**\n * `zitadel doctor` — verify generated files and local state.\n *\n * Runs every registered {@link SANITY_CHECKS} entry and emits the aggregate\n * result; if any check fails it throws `E_VALIDATION` carrying the full check\n * details. With `--fix`, each failing check first attempts its own repair (a\n * no-op for checks with no safe automatic remedy), then the battery re-runs.\n *\n * The `--fix` loop is best-effort: a repair that throws (e.g. a missing\n * prerequisite file the check itself would also flag) is logged at debug\n * level and skipped, not propagated — the post-fix re-verify still reports\n * whatever remains broken.\n */\nexport default class Doctor extends BaseCommand {\n static override description = \"Verify local runtime and project state.\";\n static override flags = {\n fix: Flags.boolean({ description: \"Re-apply missing managed files.\" }),\n image: Flags.string({ description: \"Container image to check.\" }),\n port: Flags.integer({ description: \"Local HTTP port.\", default: DEFAULT_LOCAL_SERVER_PORT }),\n };\n\n async run(): Promise<JsonEnvelope> {\n const { flags } = await this.parse(Doctor);\n const port = flags.port ?? DEFAULT_LOCAL_SERVER_PORT;\n await this.toMeta(flags, { resolveServer: false, source: localServerUrl(port) });\n const { cwd, dryRun } = this.meta;\n const image =\n flags.image ??\n this.meta.env.ZITADEL_LOCAL_IMAGE ??\n defaultLocalServerImageForCliVersion(this.meta.cliVersion);\n const runtimeChecks = await runLocalRuntimeChecks(cwd, image, port);\n const hasConfig = await hasZitadelConfig(cwd);\n const ctx: CheckContext = { cwd, orca: createOrca(), cliVersion: this.meta.cliVersion, dryRun };\n\n if (hasConfig && flags.fix) {\n const before = await Promise.all(SANITY_CHECKS.map((check) => check.run(ctx)));\n for (const [index, check] of SANITY_CHECKS.entries()) {\n if (before[index]?.status !== \"fail\") {\n continue;\n }\n try {\n await check.fix(ctx);\n } catch (error) {\n consola.debug(`doctor --fix: ${check.name} repair failed`, error);\n }\n }\n }\n\n const projectChecks = hasConfig\n ? await Promise.all(SANITY_CHECKS.map((check) => check.run(ctx)))\n : [];\n const checks = [...runtimeChecks, ...projectChecks];\n const failed = checks.filter((check) => check.status === \"fail\");\n const warnings = checks.filter((check) => check.status === \"warn\");\n const data = {\n title:\n failed.length > 0\n ? \"Zitadel doctor found issues.\"\n : warnings.length > 0\n ? \"Zitadel doctor passed with warnings.\"\n : \"Zitadel doctor passed.\",\n ok: failed.length === 0,\n image,\n port,\n project: {\n lifecycle: hasConfig ? \"configured\" : \"not-configured\",\n },\n checks,\n };\n\n if (failed.length > 0) {\n const advice = failureAdvice(failed, image, port, this.meta.cliVersion);\n throw new ZitadelError(\"E_VALIDATION\", \"Zitadel doctor found issues\", {\n hint: advice.hint,\n nextCommands: advice.nextCommands,\n details: data,\n });\n }\n\n return this.emit({\n status: \"ok\",\n data,\n warnings: warnings.map((warning) => `${warning.name}: ${warning.message}`),\n });\n }\n}\n\nfunction failureAdvice(\n failed: CheckOutcome[],\n image: string,\n port: number,\n cliVersion: string,\n): { hint: string; nextCommands: string[] } {\n const failedNames = new Set(failed.map((check) => check.name));\n\n if (failedNames.has(\"docker-cli\")) {\n return {\n hint: \"Docker is required for `zitadel start`, but the Docker daemon is not reachable. Install or start Docker, then rerun `zitadel doctor`.\",\n nextCommands: [\"docker version\", publicCliCommand(\"doctor\", cliVersion)],\n };\n }\n\n if (failedNames.has(\"image\")) {\n return {\n hint: \"The local Zitadel image is not available. Check Docker registry access, build it locally, or pass --image / ZITADEL_LOCAL_IMAGE.\",\n nextCommands: [`docker pull ${image}`, publicCliCommand(\"doctor\", cliVersion)],\n };\n }\n\n if (failedNames.has(\"state-dir\")) {\n return {\n hint: \"The local Zitadel state directory is not writable. Fix directory permissions, then rerun `zitadel doctor`.\",\n nextCommands: [publicCliCommand(\"doctor\", cliVersion)],\n };\n }\n\n if (failedNames.has(\"port\")) {\n const fallbackPort = port === DEFAULT_LOCAL_SERVER_PORT ? port + 1 : DEFAULT_LOCAL_SERVER_PORT;\n return {\n hint: `Port ${String(port)} is already in use. Stop the process using it, or choose another port for local Zitadel.`,\n nextCommands: [publicCliCommand(`doctor --port ${String(fallbackPort)}`, cliVersion)],\n };\n }\n\n if (failedNames.has(\"runtime\")) {\n return {\n hint: \"Existing local runtime metadata was found, but the local Zitadel server is not healthy. Start it again or reset stale local data.\",\n nextCommands: [\n publicCliCommand(\"start\", cliVersion),\n publicCliCommand(\"reset --force\", cliVersion),\n ],\n };\n }\n\n const hasProjectFailure = failed.some((check) => !LOCAL_RUNTIME_CHECK_NAMES.has(check.name));\n if (hasProjectFailure) {\n return {\n hint: `Run \\`${publicCliCommand(\"doctor --fix\", cliVersion)}\\` to re-apply missing managed files.`,\n nextCommands: [publicCliCommand(\"doctor --fix\", cliVersion)],\n };\n }\n\n return {\n hint: \"Fix the reported checks, then rerun `zitadel doctor`.\",\n nextCommands: [publicCliCommand(\"doctor\", cliVersion)],\n };\n}\n\nasync function runLocalRuntimeChecks(\n cwd: string,\n image: string,\n port: number,\n): Promise<CheckOutcome[]> {\n const runtime = await readRuntimeMetadata(cwd);\n const docker = await check(\n \"docker-cli\",\n \"Docker is reachable\",\n async () => {\n let result: Awaited<ReturnType<typeof dockerAvailable>>;\n try {\n result = await dockerAvailable();\n } catch (error) {\n throw new Error(dockerUnavailableMessage(error), { cause: error });\n }\n if (result.status !== 0) {\n throw new Error(dockerUnavailableMessage(result.stderr || \"docker version failed\"));\n }\n return `Docker engine ${result.stdout.trim() || \"available\"}`;\n },\n \"warn\",\n );\n\n const imageCheck =\n docker.status === \"pass\"\n ? await check(\n \"image\",\n `Image ${image} is available`,\n async () => {\n try {\n const source = await imageAvailable(image);\n return source === \"local\"\n ? `Image ${image} is available locally`\n : `Image ${image} is available from the registry`;\n } catch (error) {\n throw new Error(imageUnavailableMessage(image, error), { cause: error });\n }\n },\n \"warn\",\n )\n : ({\n name: \"image\",\n status: \"warn\",\n message: \"Skipped image check because Docker is not reachable.\",\n } satisfies CheckOutcome);\n\n return [\n docker,\n imageCheck,\n await check(\n \"state-dir\",\n \"Local state directory is writable\",\n async () => {\n const probe = await assertLocalStateWritable(cwd);\n return probe.checkedPath === probe.targetPath\n ? `${probe.targetPath} is writable`\n : `${probe.targetPath} can be created (${probe.checkedPath} is writable)`;\n },\n \"warn\",\n ),\n await check(\n \"port\",\n `Port ${String(port)} is available`,\n async () => {\n if (runtime && (await checkLocalServerHealth(runtime.server_url))) {\n return `${runtime.server_url} is already healthy`;\n }\n if (!(await isPortAvailable(port))) {\n throw new Error(`Port ${String(port)} is already in use`);\n }\n return `Port ${String(port)} is available`;\n },\n \"warn\",\n ),\n await check(\"runtime\", \"Existing local runtime is healthy\", async () => {\n if (!runtime) {\n return \"No existing runtime metadata\";\n }\n if (!(await checkLocalServerHealth(runtime.server_url))) {\n throw new Error(`${runtime.server_url} did not respond to /healthz`);\n }\n return `${runtime.server_url} is healthy`;\n }),\n ];\n}\n\nasync function check(\n name: string,\n fallback: string,\n run: () => Promise<string>,\n failureStatus: \"warn\" | \"fail\" = \"fail\",\n): Promise<CheckOutcome> {\n try {\n return { name, status: \"pass\", message: await run() };\n } catch (error) {\n return {\n name,\n status: failureStatus,\n message: error instanceof Error ? error.message : fallback,\n };\n }\n}\n\nfunction dockerUnavailableMessage(error: unknown): string {\n const detail = error instanceof Error ? error.message : String(error);\n const suffix = detail.trim() ? ` (${detail.trim()})` : \"\";\n return `Docker is not reachable${suffix}; \\`zitadel start\\` needs Docker, but cloud setup can continue.`;\n}\n\nfunction imageUnavailableMessage(image: string, error: unknown): string {\n const detail = error instanceof Error ? error.message : String(error);\n const suffix = detail.trim() ? ` (${detail.trim()})` : \"\";\n return `Image ${image} is not available to Docker${suffix}; \\`zitadel start\\` may need a pull or a different image.`;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"doctor.mjs","names":[],"sources":["../../src/commands/doctor/checks/types.ts","../../src/commands/doctor/checks/config.ts","../../src/commands/doctor/checks/secret.ts","../../src/commands/doctor/checks/secret-permissions.ts","../../src/commands/doctor/checks/gitignore.ts","../../src/commands/doctor/checks/env-example.ts","../../src/commands/doctor/checks/framework.ts","../../src/commands/doctor/patch-context.ts","../../src/commands/doctor/checks/dependency.ts","../../src/commands/doctor/checks/project-match.ts","../../src/commands/doctor/checks/index.ts","../../src/commands/doctor/index.ts"],"sourcesContent":["import type { Orca } from \"../../../lib/orca\";\n\n/** Pass/fail/advisory outcome of a single {@link SanityCheck}. */\nexport type CheckOutcome = {\n name: string;\n status: \"pass\" | \"warn\" | \"fail\";\n message: string;\n path?: string;\n};\n\n/** Everything a check needs to inspect or repair a project. */\nexport type CheckContext = {\n readonly cwd: string;\n readonly orca: Orca;\n readonly cliVersion: string;\n /** When true, {@link SanityCheck.fix} must preview without writing. */\n readonly dryRun: boolean;\n};\n\n/**\n * One diagnostic the `doctor` command runs. Each concrete check is a small\n * standalone class that both verifies its concern ({@link run}) and knows how\n * to repair it ({@link fix}); the command executes every registered check,\n * aggregates the {@link CheckOutcome}s, and (under `--fix`) repairs the ones\n * that failed.\n */\nexport interface SanityCheck {\n /** Stable identifier surfaced in logs and the JSON envelope. */\n readonly name: string;\n run(ctx: CheckContext): Promise<CheckOutcome>;\n /** Repair what this check verifies. A no-op when there is no safe auto-fix. */\n fix(ctx: CheckContext): Promise<void>;\n}\n\n/**\n * Base class for checks: subclasses declare `name`, `path`, and a success\n * `summary`, and implement the single {@link verify} method that throws on\n * failure. {@link run} wraps it so a thrown error becomes a `fail` outcome\n * carrying the error message, and success becomes a `pass` with `summary`.\n *\n * {@link fix} defaults to a no-op: checks whose failure has no safe automatic\n * remedy (a missing secret, an invalid user schema) simply do not override it.\n */\nexport abstract class AbstractSanityCheck implements SanityCheck {\n abstract readonly name: string;\n abstract readonly path: string;\n protected abstract readonly summary: string;\n\n /** Throw to signal failure; the thrown message is surfaced to the user. */\n protected abstract verify(ctx: CheckContext): Promise<void>;\n\n async run(ctx: CheckContext): Promise<CheckOutcome> {\n try {\n await this.verify(ctx);\n return { name: this.name, status: \"pass\", message: this.summary, path: this.path };\n } catch (error) {\n return {\n name: this.name,\n status: \"fail\",\n message: error instanceof Error ? error.message : String(error),\n path: this.path,\n };\n }\n }\n\n async fix(_ctx: CheckContext): Promise<void> {\n return;\n }\n}\n","import { readZitadelConfig } from \"../../../lib/project\";\nimport { AbstractSanityCheck, type CheckContext } from \"./types\";\n\n/** Verifies `zitadel.json` exists and parses. */\nexport class ConfigCheck extends AbstractSanityCheck {\n readonly name = \"config\";\n readonly path = \"zitadel.json\";\n protected readonly summary = \"zitadel.json parses\";\n\n protected async verify(ctx: CheckContext): Promise<void> {\n await readZitadelConfig(ctx.cwd);\n }\n}\n","import { readZitadelSecret } from \"../../../lib/project\";\nimport { AbstractSanityCheck, type CheckContext } from \"./types\";\n\n/** Verifies `.zitadel/secret` exists and parses. */\nexport class SecretCheck extends AbstractSanityCheck {\n readonly name = \"secret\";\n readonly path = \".zitadel/secret\";\n protected readonly summary = \".zitadel/secret parses\";\n\n protected async verify(ctx: CheckContext): Promise<void> {\n await readZitadelSecret(ctx.cwd);\n }\n}\n","import { chmod, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { AbstractSanityCheck, type CheckContext } from \"./types\";\n\n/** Verifies `.zitadel/secret` is locked down to `0600`, and re-locks it on fix. */\nexport class SecretPermissionsCheck extends AbstractSanityCheck {\n readonly name = \"secret-permissions\";\n readonly path = \".zitadel/secret\";\n protected readonly summary = \".zitadel/secret has 0600 permissions\";\n\n protected async verify(ctx: CheckContext): Promise<void> {\n const mode = (await stat(join(ctx.cwd, \".zitadel/secret\"))).mode & 0o777;\n if (mode !== 0o600) {\n throw new Error(`expected 0600, got ${mode.toString(8)}`);\n }\n }\n\n override async fix(ctx: CheckContext): Promise<void> {\n if (ctx.dryRun) {\n return;\n }\n await chmod(join(ctx.cwd, \".zitadel/secret\"), 0o600);\n }\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { AbstractSanityCheck, type CheckContext } from \"./types\";\n\n/** The entries `.gitignore` must carry to keep secrets and env files untracked. */\nconst REQUIRED_ENTRIES = [\".zitadel/secret\", \".env*\", \"!.env.example\"];\n\n/** Verifies `.gitignore` excludes the local secret and env files; appends any missing. */\nexport class GitignoreCheck extends AbstractSanityCheck {\n readonly name = \"gitignore\";\n readonly path = \".gitignore\";\n protected readonly summary = \".gitignore protects local secret/env files\";\n\n protected async verify(ctx: CheckContext): Promise<void> {\n const lines = (await readFile(join(ctx.cwd, \".gitignore\"), \"utf8\")).split(/\\r?\\n/g);\n for (const entry of REQUIRED_ENTRIES) {\n if (!lines.includes(entry)) {\n throw new Error(`missing ${entry}`);\n }\n }\n }\n\n override async fix(ctx: CheckContext): Promise<void> {\n const path = join(ctx.cwd, \".gitignore\");\n const existing = await readFile(path, \"utf8\").catch(() => \"\");\n const lines = existing.split(/\\r?\\n/g);\n const missing = REQUIRED_ENTRIES.filter((entry) => !lines.includes(entry));\n if (missing.length === 0 || ctx.dryRun) {\n return;\n }\n const prefix = existing.length > 0 && !existing.endsWith(\"\\n\") ? \"\\n\" : \"\";\n await writeFile(path, `${existing}${prefix}${missing.join(\"\\n\")}\\n`);\n }\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { AbstractSanityCheck, type CheckContext } from \"./types\";\n\n/** The keys `.env.example` must document for a Zitadel-managed project. */\nconst REQUIRED_KEYS = [\"ZITADEL_PROJECT_ID\", \"ZITADEL_ENVIRONMENT\", \"ZITADEL_ISSUER\"];\n\n/** Verifies `.env.example` documents the required Zitadel keys; appends any missing. */\nexport class EnvExampleCheck extends AbstractSanityCheck {\n readonly name = \"env-example\";\n readonly path = \".env.example\";\n protected readonly summary = \".env.example references required keys\";\n\n protected async verify(ctx: CheckContext): Promise<void> {\n const contents = await readFile(join(ctx.cwd, \".env.example\"), \"utf8\");\n for (const key of REQUIRED_KEYS) {\n if (!contents.includes(`${key}=`)) {\n throw new Error(`missing ${key}`);\n }\n }\n }\n\n override async fix(ctx: CheckContext): Promise<void> {\n const path = join(ctx.cwd, \".env.example\");\n const existing = await readFile(path, \"utf8\").catch(() => \"\");\n const missing = REQUIRED_KEYS.filter((key) => !existing.includes(`${key}=`));\n if (missing.length === 0 || ctx.dryRun) {\n return;\n }\n const prefix = existing.length > 0 && !existing.endsWith(\"\\n\") ? \"\\n\" : \"\";\n await writeFile(path, `${existing}${prefix}${missing.map((key) => `${key}=`).join(\"\\n\")}\\n`);\n }\n}\n","import { isObject } from \"../../../lib/json\";\nimport { readZitadelConfig } from \"../../../lib/project\";\nimport { AbstractSanityCheck, type CheckContext } from \"./types\";\n\n/** Verifies the framework detected on disk matches the one recorded in config. */\nexport class FrameworkCheck extends AbstractSanityCheck {\n readonly name = \"framework\";\n readonly path = \"zitadel.json\";\n protected readonly summary = \"Detected framework matches recorded framework\";\n\n protected async verify(ctx: CheckContext): Promise<void> {\n const config = await readZitadelConfig(ctx.cwd);\n const detected = await ctx.orca.detect(ctx.cwd);\n const recorded = isObject(config.framework) ? config.framework.id : undefined;\n if (recorded !== detected.id) {\n throw new Error(`expected ${String(recorded)}, detected ${detected.id}`);\n }\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { issuerFromPort, type FrameworkFacts, type Orca } from \"../../lib/orca\";\nimport type { PatchContext } from \"../../lib/orca/patchers/types\";\nimport { readDevelopmentIssuer, readRendererId, readZitadelConfig, readZitadelSecret } from \"../../lib/project\";\n\n/**\n * Reconstructs a {@link PatchContext} from the on-disk project (config, secret)\n * plus fresh framework detection, so a patcher repair can rebuild its plan.\n * Used by the dependency check's `fix`, which reclaims the framework-specific\n * SDK package via `patcher.repair`. The user schema and flow definition are\n * server-owned and no longer scaffolded locally, so nothing here reads them.\n */\nexport async function loadPatchContext(\n cwd: string,\n orca: Orca,\n cliVersion: string,\n): Promise<PatchContext> {\n const config = await readZitadelConfig(cwd);\n const secret = await readZitadelSecret(cwd);\n const framework = await orca.detect(cwd);\n return {\n framework,\n rendererId: readRendererId(config),\n issuer: await resolveIssuer(cwd, config, framework),\n server: typeof config.server === \"string\" ? config.server : \"\",\n cliVersion,\n project: {\n id: secret.project_id,\n projectSecret: secret.project_secret,\n previewSecret: secret.preview_secret,\n previewOrigins: secret.preview_origins,\n createdAt: secret.created_at,\n },\n };\n}\n\nasync function resolveIssuer(\n cwd: string,\n config: Record<string, unknown>,\n facts: FrameworkFacts,\n): Promise<string> {\n const fromConfig = readDevelopmentIssuer(config);\n if (fromConfig && fromConfig.length > 0) {\n return fromConfig;\n }\n const state = await readState(cwd);\n if (typeof state?.dev_port === \"number\") {\n return issuerFromPort(state.dev_port);\n }\n return facts.url;\n}\n\nasync function readState(cwd: string): Promise<{ dev_port?: number } | undefined> {\n try {\n const contents = await readFile(join(cwd, \".zitadel/state.json\"), \"utf8\");\n return JSON.parse(contents) as { dev_port?: number };\n } catch {\n return undefined;\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { loadPatchContext } from \"../patch-context\";\nimport { AbstractSanityCheck, type CheckContext } from \"./types\";\n\n/**\n * Verifies the project still declares a Zitadel SDK dependency in\n * `package.json`. The patcher adds a scoped package (e.g.\n * `@zitadel/sdk-next`); the check is generic over the `@zitadel*`\n * scope so any framework renderer's dependency satisfies it.\n */\nexport class DependencyCheck extends AbstractSanityCheck {\n readonly name = \"dependency\";\n readonly path = \"package.json\";\n protected readonly summary = \"package.json depends on a Zitadel SDK package\";\n\n protected async verify(ctx: CheckContext): Promise<void> {\n const pkg = JSON.parse(await readFile(join(ctx.cwd, \"package.json\"), \"utf8\")) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const names = [\n ...Object.keys(pkg.dependencies ?? {}),\n ...Object.keys(pkg.devDependencies ?? {}),\n ];\n if (!names.some((name) => name.startsWith(\"@zitadel\"))) {\n throw new Error(\"no @zitadel* dependency found in package.json\");\n }\n }\n\n /**\n * Repairs by reclaiming the patcher's managed artifacts: rebuilds the\n * `PatchContext` from disk and calls `patcher.repair`, which re-adds the\n * SDK dependency via its `add-dep` op. The exact package name is framework\n * + renderer specific and known only to the patcher (which deliberately\n * hides its file-op plan behind the family-neutral `Patcher` interface),\n * so going through `repair` is the only sanctioned path.\n */\n override async fix(ctx: CheckContext): Promise<void> {\n const patchCtx = await loadPatchContext(ctx.cwd, ctx.orca, ctx.cliVersion);\n await ctx.orca.patcherFor(patchCtx.framework.id).repair(patchCtx, {\n cwd: ctx.cwd,\n dryRun: ctx.dryRun,\n force: true,\n });\n }\n}\n","import { readZitadelConfig, readZitadelSecret } from \"../../../lib/project\";\nimport { AbstractSanityCheck, type CheckContext } from \"./types\";\n\n/** Verifies `.zitadel/secret`'s project_id matches `zitadel.json`'s project. */\nexport class ProjectMatchCheck extends AbstractSanityCheck {\n readonly name = \"project-match\";\n readonly path = \".zitadel/secret\";\n protected readonly summary = \".zitadel/secret project_id matches zitadel.json project\";\n\n protected async verify(ctx: CheckContext): Promise<void> {\n const config = await readZitadelConfig(ctx.cwd);\n const secret = await readZitadelSecret(ctx.cwd);\n const configProject = typeof config.project === \"string\" ? config.project : undefined;\n if (secret.project_id !== configProject) {\n throw new Error(\".zitadel/secret project_id does not match zitadel.json project\");\n }\n }\n}\n","/**\n * Public surface for the doctor sanity checks. The `doctor` command imports\n * {@link SANITY_CHECKS} and runs every entry, aggregating the outcomes. Each\n * check is a small standalone class (see its own file); add a new diagnostic\n * by writing a class and appending an instance to the registry below.\n */\nimport type { SanityCheck } from \"./types\";\nimport { ConfigCheck } from \"./config\";\nimport { SecretCheck } from \"./secret\";\nimport { SecretPermissionsCheck } from \"./secret-permissions\";\nimport { GitignoreCheck } from \"./gitignore\";\nimport { EnvExampleCheck } from \"./env-example\";\nimport { FrameworkCheck } from \"./framework\";\nimport { DependencyCheck } from \"./dependency\";\nimport { ProjectMatchCheck } from \"./project-match\";\n\nexport type { SanityCheck, CheckContext, CheckOutcome } from \"./types\";\nexport { AbstractSanityCheck } from \"./types\";\nexport { ConfigCheck } from \"./config\";\nexport { SecretCheck } from \"./secret\";\nexport { SecretPermissionsCheck } from \"./secret-permissions\";\nexport { GitignoreCheck } from \"./gitignore\";\nexport { EnvExampleCheck } from \"./env-example\";\nexport { FrameworkCheck } from \"./framework\";\nexport { SchemaCheck } from \"./schema\";\nexport { DependencyCheck } from \"./dependency\";\nexport { ProjectMatchCheck } from \"./project-match\";\n\n/** Every diagnostic the `doctor` command runs, in display order. */\nexport const SANITY_CHECKS: ReadonlyArray<SanityCheck> = [\n new ConfigCheck(),\n new SecretCheck(),\n new SecretPermissionsCheck(),\n new GitignoreCheck(),\n new EnvExampleCheck(),\n new FrameworkCheck(),\n // SchemaCheck is disabled: the user schema is now provisioned server-side\n // and no longer scaffolded into `.zitadel/schemas/user.json`, so there is\n // no local file to verify. The check is kept (imported/exported below) for\n // the future pull-based workflow that will re-introduce local resources.\n // new SchemaCheck(),\n new DependencyCheck(),\n new ProjectMatchCheck(),\n];\n","import { Flags } from \"@oclif/core\";\nimport consola from \"consola\";\n\nimport { ZitadelError } from \"../../lib/errors\";\nimport { assertServerPackageAvailable } from \"../../lib/local-server/binary\";\nimport { dockerAvailable, imageAvailable } from \"../../lib/local-server/docker\";\nimport {\n dockerRuntimeGuidance,\n dockerUnavailableMessage,\n} from \"../../lib/local-server/docker-guidance\";\nimport {\n DEFAULT_LOCAL_SERVER_PORT,\n assertLocalStateWritable,\n checkLocalServerHealth,\n defaultLocalServerImageForCliVersion,\n isPortAvailable,\n localServerUrl,\n readRuntimeMetadata,\n type RuntimeBackend,\n} from \"../../lib/local-server/runtime\";\nimport { BaseCommand, type JsonEnvelope } from \"../../lib/oclif\";\nimport { createOrca } from \"../../lib/orca\";\nimport { hasZitadelConfig } from \"../../lib/project\";\nimport { publicCliCommand } from \"../../lib/public-cli\";\nimport { SANITY_CHECKS, type CheckContext, type CheckOutcome } from \"./checks\";\n\nconst LOCAL_RUNTIME_CHECK_NAMES = new Set([\n \"server-binary\",\n \"docker-cli\",\n \"image\",\n \"state-dir\",\n \"port\",\n \"runtime\",\n]);\n\n/**\n * `zitadel doctor` — verify generated files and local state.\n *\n * Runs every registered {@link SANITY_CHECKS} entry and emits the aggregate\n * result; if any check fails it throws `E_VALIDATION` carrying the full check\n * details. With `--fix`, each failing check first attempts its own repair (a\n * no-op for checks with no safe automatic remedy), then the battery re-runs.\n *\n * The `--fix` loop is best-effort: a repair that throws (e.g. a missing\n * prerequisite file the check itself would also flag) is logged at debug\n * level and skipped, not propagated — the post-fix re-verify still reports\n * whatever remains broken.\n */\nexport default class Doctor extends BaseCommand {\n static override description = \"Verify local runtime and project state.\";\n static override flags = {\n fix: Flags.boolean({ description: \"Re-apply missing managed files.\" }),\n image: Flags.string({ description: \"Container image to check.\" }),\n port: Flags.integer({ description: \"Local HTTP port.\", default: DEFAULT_LOCAL_SERVER_PORT }),\n runtime: Flags.string({\n description: \"Local runtime backend.\",\n options: [\"binary\", \"docker\"],\n }),\n };\n\n async run(): Promise<JsonEnvelope> {\n const { flags } = await this.parse(Doctor);\n const port = flags.port ?? DEFAULT_LOCAL_SERVER_PORT;\n await this.toMeta(flags, { resolveServer: false, source: localServerUrl(port) });\n const { cwd, dryRun } = this.meta;\n const existingRuntime = await readRuntimeMetadata(cwd);\n const runtimeBackend = resolveRuntimeBackend({\n runtime: flags.runtime,\n image: flags.image,\n envImage: this.meta.env.ZITADEL_LOCAL_IMAGE,\n existingRuntime,\n });\n const image =\n flags.image ??\n this.meta.env.ZITADEL_LOCAL_IMAGE ??\n defaultLocalServerImageForCliVersion(this.meta.cliVersion);\n const runtimeChecks = await runLocalRuntimeChecks(cwd, runtimeBackend, image, port);\n const hasConfig = await hasZitadelConfig(cwd);\n const ctx: CheckContext = { cwd, orca: createOrca(), cliVersion: this.meta.cliVersion, dryRun };\n\n if (hasConfig && flags.fix) {\n const before = await Promise.all(SANITY_CHECKS.map((check) => check.run(ctx)));\n for (const [index, check] of SANITY_CHECKS.entries()) {\n if (before[index]?.status !== \"fail\") {\n continue;\n }\n try {\n await check.fix(ctx);\n } catch (error) {\n consola.debug(`doctor --fix: ${check.name} repair failed`, error);\n }\n }\n }\n\n const projectChecks = hasConfig\n ? await Promise.all(SANITY_CHECKS.map((check) => check.run(ctx)))\n : [];\n const checks = [...runtimeChecks, ...projectChecks];\n const failed = checks.filter((check) => check.status === \"fail\");\n const warnings = checks.filter((check) => check.status === \"warn\");\n const warningAdvice = advisoryForWarnings(warnings, this.meta.cliVersion);\n const data = {\n title:\n failed.length > 0\n ? \"Zitadel doctor found issues.\"\n : warnings.length > 0\n ? \"Zitadel doctor passed with warnings.\"\n : \"Zitadel doctor passed.\",\n ok: failed.length === 0,\n runtime: runtimeBackend,\n ...(runtimeBackend === \"docker\" ? { image } : {}),\n port,\n project: {\n lifecycle: hasConfig ? \"configured\" : \"not-configured\",\n },\n checks,\n ...(warningAdvice\n ? {\n next_actions: warningAdvice.nextActions,\n next_commands: warningAdvice.nextCommands,\n }\n : {}),\n };\n\n if (failed.length > 0) {\n const advice = failureAdvice(failed, image, port, this.meta.cliVersion);\n throw new ZitadelError(\"E_VALIDATION\", \"Zitadel doctor found issues\", {\n hint: advice.hint,\n nextCommands: advice.nextCommands,\n details: data,\n });\n }\n\n return this.emit({\n status: \"ok\",\n data,\n warnings: warnings.map((warning) => `${warning.name}: ${warning.message}`),\n });\n }\n}\n\nfunction failureAdvice(\n failed: CheckOutcome[],\n image: string,\n port: number,\n cliVersion: string,\n): { hint: string; nextCommands: string[] } {\n const failedNames = new Set(failed.map((check) => check.name));\n\n if (failedNames.has(\"server-binary\")) {\n return {\n hint: \"The Zitadel server npm package is not available. Reinstall the CLI package, then retry.\",\n nextCommands: [publicCliCommand(\"doctor\", cliVersion)],\n };\n }\n\n if (failedNames.has(\"docker-cli\")) {\n const advice = dockerRuntimeGuidance(\"doctor\", cliVersion);\n return {\n hint: advice.hint,\n nextCommands: advice.nextCommands,\n };\n }\n\n if (failedNames.has(\"image\")) {\n return {\n hint: \"The local Zitadel image is not available. Check Docker registry access, build it locally, or pass --image / ZITADEL_LOCAL_IMAGE.\",\n nextCommands: [`docker pull ${image}`, publicCliCommand(\"doctor\", cliVersion)],\n };\n }\n\n if (failedNames.has(\"state-dir\")) {\n return {\n hint: \"The local Zitadel state directory is not writable. Fix directory permissions, then rerun `zitadel doctor`.\",\n nextCommands: [publicCliCommand(\"doctor\", cliVersion)],\n };\n }\n\n if (failedNames.has(\"port\")) {\n const fallbackPort = port === DEFAULT_LOCAL_SERVER_PORT ? port + 1 : DEFAULT_LOCAL_SERVER_PORT;\n return {\n hint: `Port ${String(port)} is already in use. Stop the process using it, or choose another port for local Zitadel.`,\n nextCommands: [publicCliCommand(`doctor --port ${String(fallbackPort)}`, cliVersion)],\n };\n }\n\n if (failedNames.has(\"runtime\")) {\n return {\n hint: \"Existing local runtime metadata was found, but the local Zitadel server is not healthy. Start it again or reset stale local data.\",\n nextCommands: [\n publicCliCommand(\"start\", cliVersion),\n publicCliCommand(\"reset --force\", cliVersion),\n ],\n };\n }\n\n const hasProjectFailure = failed.some((check) => !LOCAL_RUNTIME_CHECK_NAMES.has(check.name));\n if (hasProjectFailure) {\n return {\n hint: `Run \\`${publicCliCommand(\"doctor --fix\", cliVersion)}\\` to re-apply missing managed files.`,\n nextCommands: [publicCliCommand(\"doctor --fix\", cliVersion)],\n };\n }\n\n return {\n hint: \"Fix the reported checks, then rerun `zitadel doctor`.\",\n nextCommands: [publicCliCommand(\"doctor\", cliVersion)],\n };\n}\n\nfunction advisoryForWarnings(\n warnings: CheckOutcome[],\n cliVersion: string,\n): { nextActions: string[]; nextCommands: string[] } | undefined {\n if (!warnings.some((check) => check.name === \"docker-cli\")) {\n return undefined;\n }\n const advice = dockerRuntimeGuidance(\"doctor\", cliVersion);\n return { nextActions: advice.nextActions, nextCommands: advice.nextCommands };\n}\n\nasync function runLocalRuntimeChecks(\n cwd: string,\n runtimeBackend: RuntimeBackend,\n image: string,\n port: number,\n): Promise<CheckOutcome[]> {\n const runtime = await readRuntimeMetadata(cwd);\n if (runtimeBackend === \"binary\") {\n return [\n await check(\"server-binary\", \"Server npm package is available\", async () => {\n const version = await assertServerPackageAvailable();\n return `@zitadel/server ${version} is available`;\n }),\n await check(\n \"state-dir\",\n \"Local state directory is writable\",\n async () => {\n const probe = await assertLocalStateWritable(cwd);\n return probe.checkedPath === probe.targetPath\n ? `${probe.targetPath} is writable`\n : `${probe.targetPath} can be created (${probe.checkedPath} is writable)`;\n },\n \"warn\",\n ),\n await check(\n \"port\",\n `Port ${String(port)} is available`,\n async () => {\n if (runtime && (await checkLocalServerHealth(runtime.server_url))) {\n return `${runtime.server_url} is already healthy`;\n }\n if (!(await isPortAvailable(port))) {\n throw new Error(`Port ${String(port)} is already in use`);\n }\n return `Port ${String(port)} is available`;\n },\n \"warn\",\n ),\n await checkRuntime(runtime, runtimeBackend),\n ];\n }\n\n const docker = await check(\n \"docker-cli\",\n \"Docker is reachable\",\n async () => {\n let result: Awaited<ReturnType<typeof dockerAvailable>>;\n try {\n result = await dockerAvailable();\n } catch (error) {\n throw new Error(dockerUnavailableMessage(error), { cause: error });\n }\n if (result.status !== 0) {\n throw new Error(dockerUnavailableMessage(result.stderr || \"docker version failed\"));\n }\n return `Docker engine ${result.stdout.trim() || \"available\"}`;\n },\n \"warn\",\n );\n\n const imageCheck =\n docker.status === \"pass\"\n ? await check(\n \"image\",\n `Image ${image} is available`,\n async () => {\n try {\n const source = await imageAvailable(image);\n return source === \"local\"\n ? `Image ${image} is available locally`\n : `Image ${image} is available from the registry`;\n } catch (error) {\n throw new Error(imageUnavailableMessage(image, error), { cause: error });\n }\n },\n \"warn\",\n )\n : ({\n name: \"image\",\n status: \"warn\",\n message: \"Skipped image check because Docker is not reachable.\",\n } satisfies CheckOutcome);\n\n return [\n docker,\n imageCheck,\n await check(\n \"state-dir\",\n \"Local state directory is writable\",\n async () => {\n const probe = await assertLocalStateWritable(cwd);\n return probe.checkedPath === probe.targetPath\n ? `${probe.targetPath} is writable`\n : `${probe.targetPath} can be created (${probe.checkedPath} is writable)`;\n },\n \"warn\",\n ),\n await check(\n \"port\",\n `Port ${String(port)} is available`,\n async () => {\n if (runtime && (await checkLocalServerHealth(runtime.server_url))) {\n return `${runtime.server_url} is already healthy`;\n }\n if (!(await isPortAvailable(port))) {\n throw new Error(`Port ${String(port)} is already in use`);\n }\n return `Port ${String(port)} is available`;\n },\n \"warn\",\n ),\n await checkRuntime(runtime, runtimeBackend),\n ];\n}\n\nasync function checkRuntime(\n runtime: { backend: RuntimeBackend; server_url: string } | undefined,\n runtimeBackend: RuntimeBackend,\n): Promise<CheckOutcome> {\n return check(\"runtime\", \"Existing local runtime is healthy\", async () => {\n if (!runtime) {\n return \"No existing runtime metadata\";\n }\n if (runtime.backend !== runtimeBackend) {\n throw new Error(\n `Existing local runtime uses ${runtime.backend}; run start --runtime ${runtimeBackend} to switch backends.`,\n );\n }\n if (!(await checkLocalServerHealth(runtime.server_url))) {\n throw new Error(`${runtime.server_url} did not respond to /healthz`);\n }\n return `${runtime.server_url} is healthy`;\n });\n}\n\nfunction resolveRuntimeBackend(input: {\n runtime: unknown;\n image: string | undefined;\n envImage: string | undefined;\n existingRuntime: { backend: RuntimeBackend } | undefined;\n}): RuntimeBackend {\n if (input.runtime === \"binary\" || input.runtime === \"docker\") {\n return input.runtime;\n }\n if (input.existingRuntime) {\n return input.existingRuntime.backend;\n }\n if (input.image || input.envImage) {\n return \"docker\";\n }\n return \"binary\";\n}\n\nasync function check(\n name: string,\n fallback: string,\n run: () => Promise<string>,\n failureStatus: \"warn\" | \"fail\" = \"fail\",\n): Promise<CheckOutcome> {\n try {\n return { name, status: \"pass\", message: await run() };\n } catch (error) {\n return {\n name,\n status: failureStatus,\n message: error instanceof Error ? error.message : fallback,\n };\n }\n}\n\nfunction imageUnavailableMessage(image: string, error: unknown): string {\n const detail = error instanceof Error ? error.message : String(error);\n const suffix = detail.trim() ? ` (${detail.trim()})` : \"\";\n return `Image ${image} is not available to Docker${suffix}; \\`zitadel start\\` may need a pull or a different image.`;\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { D as ZitadelError, t as BaseCommand } from "../oclif-2t97lHfY.mjs";
2
- import { t as createOrca } from "../orca-CYqJP4ZJ.mjs";
3
- import { a as readZitadelConfig, i as readRendererId } from "../project-IzPVR0Pr.mjs";
1
+ import { D as ZitadelError, t as BaseCommand } from "../oclif-VkCTGIEk.mjs";
2
+ import { t as createOrca } from "../orca-CfKDQRop.mjs";
3
+ import { a as readZitadelConfig, i as readRendererId } from "../project-CKAHtHML.mjs";
4
4
  import { join } from "node:path";
5
5
  import { readFile, rename, rm, stat } from "node:fs/promises";
6
6
  //#region src/commands/eject.ts
@@ -1,5 +1,5 @@
1
- import { C as resolveCwd, D as ZitadelError, h as readRuntimeMetadata, t as BaseCommand, x as publicCliCommand } from "../oclif-2t97lHfY.mjs";
2
- import { a as followContainerLogs, t as containerLogs } from "../docker--EAWr_WY.mjs";
1
+ import { C as resolveCwd, D as ZitadelError, h as readRuntimeMetadata, t as BaseCommand, x as publicCliCommand } from "../oclif-VkCTGIEk.mjs";
2
+ import { a as followContainerLogs, f as binaryLogs, p as followBinaryLogs, t as containerLogs } from "../docker-BA78SdC2.mjs";
3
3
  import { Flags } from "@oclif/core";
4
4
  //#region src/commands/logs.ts
5
5
  var Logs = class Logs extends BaseCommand {
@@ -26,19 +26,27 @@ var Logs = class Logs extends BaseCommand {
26
26
  if (!Number.isInteger(tail) || tail < 1) throw new ZitadelError("E_VALIDATION", `Invalid tail value ${String(tail)}`, { hint: "Use a positive integer." });
27
27
  if (flags.follow) {
28
28
  if (this.jsonEnabled()) throw new ZitadelError("E_VALIDATION", "Cannot stream logs with --json", { hint: "Run without --json, or omit --follow." });
29
- await followContainerLogs(runtime.container_name, tail);
29
+ if (runtime.backend === "binary") await followBinaryLogs(runtime.log_path, tail);
30
+ else await followContainerLogs(runtime.container_name, tail);
30
31
  return this.emit({
31
32
  status: "ok",
32
33
  data: { title: "Stopped following local Zitadel logs." }
33
34
  });
34
35
  }
35
- const logs = await containerLogs(runtime.container_name, tail);
36
+ const logs = runtime.backend === "binary" ? await binaryLogs(runtime.log_path, tail) : await containerLogs(runtime.container_name, tail);
36
37
  return this.emit({
37
38
  status: "ok",
38
39
  pretty: logs.trimEnd(),
39
40
  data: {
40
41
  title: "Local Zitadel server logs.",
41
- container_name: runtime.container_name,
42
+ runtime: runtime.backend === "binary" ? {
43
+ backend: runtime.backend,
44
+ pid: runtime.pid,
45
+ log_path: runtime.log_path
46
+ } : {
47
+ backend: runtime.backend,
48
+ container_name: runtime.container_name
49
+ },
42
50
  logs
43
51
  }
44
52
  });
@@ -1 +1 @@
1
- {"version":3,"file":"logs.mjs","names":[],"sources":["../../src/commands/logs.ts"],"sourcesContent":["import { Flags } from \"@oclif/core\";\n\nimport { ZitadelError } from \"../lib/errors\";\nimport { containerLogs, followContainerLogs } from \"../lib/local-server/docker\";\nimport { DEFAULT_LOCAL_SERVER_URL, readRuntimeMetadata } from \"../lib/local-server/runtime\";\nimport { BaseCommand, type JsonEnvelope } from \"../lib/oclif\";\nimport { resolveCwd } from \"../lib/paths\";\nimport { publicCliCommand } from \"../lib/public-cli\";\n\nexport default class Logs extends BaseCommand {\n static override description = \"Show local Zitadel server logs.\";\n static override flags = {\n follow: Flags.boolean({ description: \"Follow logs.\" }),\n tail: Flags.integer({ description: \"Number of lines to show.\", default: 200 }),\n };\n\n async run(): Promise<JsonEnvelope> {\n const { flags } = await this.parse(Logs);\n const cwd = resolveCwd(typeof flags.cwd === \"string\" ? flags.cwd : undefined);\n const runtime = await readRuntimeMetadata(cwd);\n await this.toMeta(flags, {\n resolveServer: false,\n source: runtime?.server_url ?? DEFAULT_LOCAL_SERVER_URL,\n });\n\n if (!runtime) {\n throw new ZitadelError(\"E_VALIDATION\", \"Local Zitadel runtime has not been started\", {\n hint: \"Run `zitadel start` first.\",\n nextCommands: [publicCliCommand(\"start\", this.meta.cliVersion)],\n });\n }\n\n const tail = flags.tail ?? 200;\n if (!Number.isInteger(tail) || tail < 1) {\n throw new ZitadelError(\"E_VALIDATION\", `Invalid tail value ${String(tail)}`, {\n hint: \"Use a positive integer.\",\n });\n }\n\n if (flags.follow) {\n if (this.jsonEnabled()) {\n throw new ZitadelError(\"E_VALIDATION\", \"Cannot stream logs with --json\", {\n hint: \"Run without --json, or omit --follow.\",\n });\n }\n await followContainerLogs(runtime.container_name, tail);\n return this.emit({\n status: \"ok\",\n data: { title: \"Stopped following local Zitadel logs.\" },\n });\n }\n\n const logs = await containerLogs(runtime.container_name, tail);\n return this.emit({\n status: \"ok\",\n pretty: logs.trimEnd(),\n data: {\n title: \"Local Zitadel server logs.\",\n container_name: runtime.container_name,\n logs,\n },\n });\n }\n}\n"],"mappings":";;;;AASA,IAAqB,OAArB,MAAqB,aAAa,YAAY;CAC5C,OAAgB,cAAc;CAC9B,OAAgB,QAAQ;EACtB,QAAQ,MAAM,QAAQ,EAAE,aAAa,gBAAgB,CAAC;EACtD,MAAM,MAAM,QAAQ;GAAE,aAAa;GAA4B,SAAS;GAAK,CAAC;EAC/E;CAED,MAAM,MAA6B;EACjC,MAAM,EAAE,UAAU,MAAM,KAAK,MAAM,KAAK;EAExC,MAAM,UAAU,MAAM,oBADV,WAAW,OAAO,MAAM,QAAQ,WAAW,MAAM,MAAM,KAAA,EACtB,CAAC;AAC9C,QAAM,KAAK,OAAO,OAAO;GACvB,eAAe;GACf,QAAQ,SAAS,cAAA;GAClB,CAAC;AAEF,MAAI,CAAC,QACH,OAAM,IAAI,aAAa,gBAAgB,8CAA8C;GACnF,MAAM;GACN,cAAc,CAAC,iBAAiB,SAAS,KAAK,KAAK,WAAW,CAAC;GAChE,CAAC;EAGJ,MAAM,OAAO,MAAM,QAAQ;AAC3B,MAAI,CAAC,OAAO,UAAU,KAAK,IAAI,OAAO,EACpC,OAAM,IAAI,aAAa,gBAAgB,sBAAsB,OAAO,KAAK,IAAI,EAC3E,MAAM,2BACP,CAAC;AAGJ,MAAI,MAAM,QAAQ;AAChB,OAAI,KAAK,aAAa,CACpB,OAAM,IAAI,aAAa,gBAAgB,kCAAkC,EACvE,MAAM,yCACP,CAAC;AAEJ,SAAM,oBAAoB,QAAQ,gBAAgB,KAAK;AACvD,UAAO,KAAK,KAAK;IACf,QAAQ;IACR,MAAM,EAAE,OAAO,yCAAyC;IACzD,CAAC;;EAGJ,MAAM,OAAO,MAAM,cAAc,QAAQ,gBAAgB,KAAK;AAC9D,SAAO,KAAK,KAAK;GACf,QAAQ;GACR,QAAQ,KAAK,SAAS;GACtB,MAAM;IACJ,OAAO;IACP,gBAAgB,QAAQ;IACxB;IACD;GACF,CAAC"}
1
+ {"version":3,"file":"logs.mjs","names":[],"sources":["../../src/commands/logs.ts"],"sourcesContent":["import { Flags } from \"@oclif/core\";\n\nimport { ZitadelError } from \"../lib/errors\";\nimport { binaryLogs, followBinaryLogs } from \"../lib/local-server/binary\";\nimport { containerLogs, followContainerLogs } from \"../lib/local-server/docker\";\nimport { DEFAULT_LOCAL_SERVER_URL, readRuntimeMetadata } from \"../lib/local-server/runtime\";\nimport { BaseCommand, type JsonEnvelope } from \"../lib/oclif\";\nimport { resolveCwd } from \"../lib/paths\";\nimport { publicCliCommand } from \"../lib/public-cli\";\n\nexport default class Logs extends BaseCommand {\n static override description = \"Show local Zitadel server logs.\";\n static override flags = {\n follow: Flags.boolean({ description: \"Follow logs.\" }),\n tail: Flags.integer({ description: \"Number of lines to show.\", default: 200 }),\n };\n\n async run(): Promise<JsonEnvelope> {\n const { flags } = await this.parse(Logs);\n const cwd = resolveCwd(typeof flags.cwd === \"string\" ? flags.cwd : undefined);\n const runtime = await readRuntimeMetadata(cwd);\n await this.toMeta(flags, {\n resolveServer: false,\n source: runtime?.server_url ?? DEFAULT_LOCAL_SERVER_URL,\n });\n\n if (!runtime) {\n throw new ZitadelError(\"E_VALIDATION\", \"Local Zitadel runtime has not been started\", {\n hint: \"Run `zitadel start` first.\",\n nextCommands: [publicCliCommand(\"start\", this.meta.cliVersion)],\n });\n }\n\n const tail = flags.tail ?? 200;\n if (!Number.isInteger(tail) || tail < 1) {\n throw new ZitadelError(\"E_VALIDATION\", `Invalid tail value ${String(tail)}`, {\n hint: \"Use a positive integer.\",\n });\n }\n\n if (flags.follow) {\n if (this.jsonEnabled()) {\n throw new ZitadelError(\"E_VALIDATION\", \"Cannot stream logs with --json\", {\n hint: \"Run without --json, or omit --follow.\",\n });\n }\n if (runtime.backend === \"binary\") {\n await followBinaryLogs(runtime.log_path, tail);\n } else {\n await followContainerLogs(runtime.container_name, tail);\n }\n return this.emit({\n status: \"ok\",\n data: { title: \"Stopped following local Zitadel logs.\" },\n });\n }\n\n const logs =\n runtime.backend === \"binary\"\n ? await binaryLogs(runtime.log_path, tail)\n : await containerLogs(runtime.container_name, tail);\n return this.emit({\n status: \"ok\",\n pretty: logs.trimEnd(),\n data: {\n title: \"Local Zitadel server logs.\",\n runtime:\n runtime.backend === \"binary\"\n ? { backend: runtime.backend, pid: runtime.pid, log_path: runtime.log_path }\n : { backend: runtime.backend, container_name: runtime.container_name },\n logs,\n },\n });\n }\n}\n"],"mappings":";;;;AAUA,IAAqB,OAArB,MAAqB,aAAa,YAAY;CAC5C,OAAgB,cAAc;CAC9B,OAAgB,QAAQ;EACtB,QAAQ,MAAM,QAAQ,EAAE,aAAa,gBAAgB,CAAC;EACtD,MAAM,MAAM,QAAQ;GAAE,aAAa;GAA4B,SAAS;GAAK,CAAC;EAC/E;CAED,MAAM,MAA6B;EACjC,MAAM,EAAE,UAAU,MAAM,KAAK,MAAM,KAAK;EAExC,MAAM,UAAU,MAAM,oBADV,WAAW,OAAO,MAAM,QAAQ,WAAW,MAAM,MAAM,KAAA,EACtB,CAAC;AAC9C,QAAM,KAAK,OAAO,OAAO;GACvB,eAAe;GACf,QAAQ,SAAS,cAAA;GAClB,CAAC;AAEF,MAAI,CAAC,QACH,OAAM,IAAI,aAAa,gBAAgB,8CAA8C;GACnF,MAAM;GACN,cAAc,CAAC,iBAAiB,SAAS,KAAK,KAAK,WAAW,CAAC;GAChE,CAAC;EAGJ,MAAM,OAAO,MAAM,QAAQ;AAC3B,MAAI,CAAC,OAAO,UAAU,KAAK,IAAI,OAAO,EACpC,OAAM,IAAI,aAAa,gBAAgB,sBAAsB,OAAO,KAAK,IAAI,EAC3E,MAAM,2BACP,CAAC;AAGJ,MAAI,MAAM,QAAQ;AAChB,OAAI,KAAK,aAAa,CACpB,OAAM,IAAI,aAAa,gBAAgB,kCAAkC,EACvE,MAAM,yCACP,CAAC;AAEJ,OAAI,QAAQ,YAAY,SACtB,OAAM,iBAAiB,QAAQ,UAAU,KAAK;OAE9C,OAAM,oBAAoB,QAAQ,gBAAgB,KAAK;AAEzD,UAAO,KAAK,KAAK;IACf,QAAQ;IACR,MAAM,EAAE,OAAO,yCAAyC;IACzD,CAAC;;EAGJ,MAAM,OACJ,QAAQ,YAAY,WAChB,MAAM,WAAW,QAAQ,UAAU,KAAK,GACxC,MAAM,cAAc,QAAQ,gBAAgB,KAAK;AACvD,SAAO,KAAK,KAAK;GACf,QAAQ;GACR,QAAQ,KAAK,SAAS;GACtB,MAAM;IACJ,OAAO;IACP,SACE,QAAQ,YAAY,WAChB;KAAE,SAAS,QAAQ;KAAS,KAAK,QAAQ;KAAK,UAAU,QAAQ;KAAU,GAC1E;KAAE,SAAS,QAAQ;KAAS,gBAAgB,QAAQ;KAAgB;IAC1E;IACD;GACF,CAAC"}
@@ -1,6 +1,6 @@
1
- import { t as BaseCommand } from "../oclif-2t97lHfY.mjs";
2
- import { o as readZitadelSecret } from "../project-IzPVR0Pr.mjs";
3
- import { a as makeSyncers, n as summarizePlan, o as environmentSchema, r as buildSyncPlan, t as renderPlan } from "../sync-Df9S8Pio.mjs";
1
+ import { t as BaseCommand } from "../oclif-VkCTGIEk.mjs";
2
+ import { o as readZitadelSecret } from "../project-CKAHtHML.mjs";
3
+ import { a as makeSyncers, n as summarizePlan, o as environmentSchema, r as buildSyncPlan, t as renderPlan } from "../sync-B5lqgQO3.mjs";
4
4
  import { Flags } from "@oclif/core";
5
5
  import { createZitadelClient } from "@zitadel/api/client";
6
6
  import { consola as consola$1 } from "consola";