@zitadel/cli 0.1.0-alpha.18 → 0.1.0-alpha.19

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 (56) hide show
  1. package/README.md +81 -33
  2. package/SKILLS.md +74 -8
  3. package/dist/{branding-BXj028-W.mjs → branding-cygSBPkV.mjs} +2 -2
  4. package/dist/{branding-BXj028-W.mjs.map → branding-cygSBPkV.mjs.map} +1 -1
  5. package/dist/{claim-state-BTGInAaN.mjs → claim-state-DlfD6Res.mjs} +2 -2
  6. package/dist/{claim-state-BTGInAaN.mjs.map → claim-state-DlfD6Res.mjs.map} +1 -1
  7. package/dist/commands/apply.mjs +4 -4
  8. package/dist/commands/branding/eject.mjs +11 -32
  9. package/dist/commands/branding/eject.mjs.map +1 -1
  10. package/dist/commands/claim.mjs +3 -3
  11. package/dist/commands/doctor.mjs +41 -18
  12. package/dist/commands/doctor.mjs.map +1 -1
  13. package/dist/commands/eject.mjs +4 -4
  14. package/dist/commands/eject.mjs.map +1 -1
  15. package/dist/commands/logs.mjs +2 -2
  16. package/dist/commands/plan.mjs +4 -4
  17. package/dist/commands/reset.mjs +2 -2
  18. package/dist/commands/schemas/list.mjs +6 -6
  19. package/dist/commands/schemas/list.mjs.map +1 -1
  20. package/dist/commands/setup.mjs +101 -143
  21. package/dist/commands/setup.mjs.map +1 -1
  22. package/dist/commands/start.mjs +3 -3
  23. package/dist/commands/status.mjs +5 -5
  24. package/dist/commands/stop.mjs +3 -3
  25. package/dist/designs-Ckz18Dpo.mjs +38 -0
  26. package/dist/designs-Ckz18Dpo.mjs.map +1 -0
  27. package/dist/{docker-Ciz9N6uI.mjs → docker-DcRGTOJa.mjs} +4 -3
  28. package/dist/docker-DcRGTOJa.mjs.map +1 -0
  29. package/dist/{environment-CuHKxtIO.mjs → environment-rjRVkJjW.mjs} +1 -1
  30. package/dist/{environment-CuHKxtIO.mjs.map → environment-rjRVkJjW.mjs.map} +1 -1
  31. package/dist/{journey-guidance-CtQUfWar.mjs → journey-guidance-BGrOX_gT.mjs} +2 -2
  32. package/dist/{journey-guidance-CtQUfWar.mjs.map → journey-guidance-BGrOX_gT.mjs.map} +1 -1
  33. package/dist/{oclif-CL6-M13m.mjs → oclif-CanO3zdt.mjs} +48 -2
  34. package/dist/oclif-CanO3zdt.mjs.map +1 -0
  35. package/dist/{orca-BWB4zOdw.mjs → orca-Cu0iW1mv.mjs} +167 -26
  36. package/dist/orca-Cu0iW1mv.mjs.map +1 -0
  37. package/dist/package-manager-DFdLcDx1.mjs +194 -0
  38. package/dist/package-manager-DFdLcDx1.mjs.map +1 -0
  39. package/dist/{ports-Cu2Y7aXQ.mjs → ports-BM20XIZb.mjs} +2 -2
  40. package/dist/{ports-Cu2Y7aXQ.mjs.map → ports-BM20XIZb.mjs.map} +1 -1
  41. package/dist/{processes-Bn2WngOi.mjs → processes-DKHPkU8O.mjs} +1 -1
  42. package/dist/{processes-Bn2WngOi.mjs.map → processes-DKHPkU8O.mjs.map} +1 -1
  43. package/dist/{project-yejJSfdJ.mjs → project-CHhot85s.mjs} +2 -2
  44. package/dist/{project-yejJSfdJ.mjs.map → project-CHhot85s.mjs.map} +1 -1
  45. package/dist/{sync-Cx2_4rXW.mjs → sync-Bd6vASgg.mjs} +456 -31
  46. package/dist/sync-Bd6vASgg.mjs.map +1 -0
  47. package/dist/{user-schema-W1OsXdpc.mjs → user-schema-DTuOsdKE.mjs} +1 -1
  48. package/dist/{user-schema-W1OsXdpc.mjs.map → user-schema-DTuOsdKE.mjs.map} +1 -1
  49. package/oclif.manifest.json +2 -2
  50. package/package.json +6 -5
  51. package/dist/docker-Ciz9N6uI.mjs.map +0 -1
  52. package/dist/oclif-CL6-M13m.mjs.map +0 -1
  53. package/dist/orca-BWB4zOdw.mjs.map +0 -1
  54. package/dist/scaffold-manifest-CKNFLX9T.mjs +0 -81
  55. package/dist/scaffold-manifest-CKNFLX9T.mjs.map +0 -1
  56. package/dist/sync-Cx2_4rXW.mjs.map +0 -1
@@ -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/dependency-version.ts","../../src/commands/doctor/checks/managed-files.ts","../../src/commands/doctor/checks/project-match.ts","../../src/lib/json-dir.ts","../../src/commands/doctor/checks/schema.ts","../../src/commands/doctor/checks/claim.ts","../../src/commands/doctor/checks/index.ts","../../src/commands/doctor/index.ts"],"sourcesContent":["import { ZitadelError, type ZitadelErrorCode } from \"../../../lib/errors\";\nimport type { Orca } from \"../../../lib/orca\";\n\n/** Pass/fail/advisory outcome of a single {@link SanityCheck}. */\nexport type CheckOutcome = {\n details?: unknown;\n name: string;\n status: \"pass\" | \"warn\" | \"fail\";\n message: string;\n path?: string;\n /**\n * Set when the failure surfaced as a typed CLI error: the error's category\n * and remedy travel through the outcome so the doctor envelope can carry\n * the advertised code (e.g. the framework floor's\n * `E_UNSUPPORTED_PROJECT_SHAPE`) and hint instead of generic advice.\n */\n code?: ZitadelErrorCode;\n hint?: 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 ...(error instanceof ZitadelError\n ? { code: error.code, ...(error.hint === undefined ? {} : { hint: error.hint }) }\n : {}),\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 { issuerFromPort, type FrameworkFacts, type Orca } from \"../../lib/orca\";\nimport type { PatchContext } from \"../../lib/orca/patchers/types\";\nimport {\n readDevelopmentIssuer,\n readPreset,\n readRendererId,\n readUseCase,\n readZitadelConfig,\n readZitadelSecret,\n} from \"../../lib/project\";\nimport { readScaffoldManifest } from \"../../lib/scaffold-manifest\";\n\n/**\n * Reconstructs a {@link PatchContext} from the on-disk project (config,\n * secret, scaffold manifest) plus fresh framework detection, so a patcher\n * repair can rebuild its plan. Used by the doctor checks' `fix` paths.\n * `preset`/`useCase` come back from `zitadel.json` and\n * `scaffoldedFramework` from the scaffold manifest, so the rebuilt plan\n * matches what setup originally emitted (a fresh-scaffolded app's home page\n * is part of the plan again, for example). Schema and flow config are\n * user-editable sync resources, not patcher inputs, so nothing here reads\n * 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 const scaffold = await readScaffoldManifest(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 scaffoldedFramework: scaffold?.scaffolded_framework,\n // Restore the posture setup recorded rather than re-deriving it — a\n // manifest-less legacy scaffold cannot answer the fresh-vs-pre-existing\n // hinge, and every scaffold before the record was full-page (ADR 044).\n posture: scaffold?.posture ?? \"page\",\n preset: readPreset(config),\n useCase: readUseCase(config),\n project: {\n id: secret.project_id,\n project_secret: secret.project_secret,\n preview_secret: secret.preview_secret,\n preview_origins: secret.preview_origins,\n created_at: 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 scaffold = await readScaffoldManifest(cwd);\n if (typeof scaffold?.dev_port === \"number\") {\n return issuerFromPort(scaffold.dev_port);\n }\n return facts.url;\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 re-applying 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. Missing-only:\n * the repair restores absent managed files as a side effect but never\n * overwrites an existing one, edited or not.\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: false,\n missingOnly: true,\n });\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport semver from \"semver\";\n\nimport type { CheckContext, CheckOutcome, SanityCheck } from \"./types\";\n\n/**\n * Verifies that exactly-pinned `@zitadel/*` dependencies match this CLI's own\n * version. The packages publish as one lockstep train, and the scaffold pins\n * the SDK at the CLI's version — but the CLI floats (`npx @zitadel/cli@alpha`)\n * while the app's pin stays put, so a newer CLI can restore files or write\n * guidance that references SDK entry points the older pinned SDK does not\n * ship (e.g. a subpath export added a train later). A mismatch therefore\n * *warns* with the exact remedy instead of leaving the skew to surface as a\n * module-not-found in the app.\n *\n * Only exact semver pins are compared: ranges, dist-tags, and `file:`/\n * `workspace:` specifiers express a deliberate resolution choice the check\n * cannot second-guess.\n *\n * Implements {@link SanityCheck} directly: the abstract base's verify-throws\n * contract can only express pass/fail, and a version skew is advisory — the\n * app keeps working on its pinned train until the user upgrades.\n */\nexport class DependencyVersionCheck implements SanityCheck {\n readonly name = \"dependency-version\";\n readonly path = \"package.json\";\n\n async run(ctx: CheckContext): Promise<CheckOutcome> {\n const base = { name: this.name, path: this.path };\n if (semver.valid(ctx.cliVersion) === null) {\n // A dev or placeholder CLI version has no train to compare against.\n return {\n ...base,\n status: \"pass\",\n message: `CLI version ${ctx.cliVersion} is not an exact release; skipping the pin comparison`,\n };\n }\n let pkg: { dependencies?: Record<string, string>; devDependencies?: Record<string, string> };\n try {\n pkg = JSON.parse(await readFile(join(ctx.cwd, \"package.json\"), \"utf8\")) as typeof pkg;\n } catch {\n // A missing or unparsable package.json is the dependency check's\n // failure to report; double-flagging the same root cause helps nobody.\n return { ...base, status: \"pass\", message: \"no package.json to compare pins against\" };\n }\n const declared = Object.entries({\n ...(pkg.dependencies ?? {}),\n ...(pkg.devDependencies ?? {}),\n }).filter(([name]) => name.startsWith(\"@zitadel/\"));\n const exact = declared.filter(([, version]) => semver.valid(version.trim()) !== null);\n const mismatched = exact.filter(\n ([, version]) => !semver.eq(version.trim(), ctx.cliVersion),\n );\n if (mismatched.length > 0) {\n const remedy = mismatched.map(([name]) => `${name}@${ctx.cliVersion}`).join(\" \");\n return {\n ...base,\n status: \"warn\",\n message:\n `${mismatched.map(([name, version]) => `${name}@${version}`).join(\", \")} ` +\n `does not match this CLI's version (${ctx.cliVersion}); scaffolded files and ` +\n `guidance target the CLI's train — update with e.g. \\`npm install ${remedy}\\``,\n details: {\n mismatched: mismatched.map(([name, version]) => ({\n name,\n declared: version,\n expected: ctx.cliVersion,\n })),\n },\n };\n }\n return {\n ...base,\n status: \"pass\",\n message:\n exact.length > 0\n ? `Zitadel package pins match the CLI version (${exact.length} compared)`\n : \"no exactly-pinned Zitadel packages to compare\",\n };\n }\n\n /**\n * No auto-fix: repair's dependency op is deliberately additive-only (it\n * never rewrites a version the user declared), so the warn message carries\n * the exact install command instead.\n */\n async fix(_ctx: CheckContext): Promise<void> {\n return;\n }\n}\n","import { readFile, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport type { ConfigWiringStatus, EjectActions } from \"../../../lib/orca/patchers/types\";\nimport { MANAGED_MARKER } from \"../../../lib/paths\";\nimport { readRendererId, readZitadelConfig } from \"../../../lib/project\";\nimport {\n hashScaffoldFile,\n readScaffoldManifest,\n writeScaffoldManifest,\n} from \"../../../lib/scaffold-manifest\";\nimport { updateScaffold } from \"../../../lib/sync/state\";\nimport type { ScaffoldFileClass, ScaffoldManifest } from \"../../../lib/sync/types\";\nimport { loadPatchContext } from \"../patch-context\";\nimport type { CheckContext, CheckOutcome, SanityCheck } from \"./types\";\n\n/**\n * Per-file classification reported in the check's `details`:\n *\n * - `pristine` — still the bytes setup wrote (manifest hash matches).\n * - `edited` — carries the managed marker but the content changed; the user\n * extended a managed file (e.g. added routes to the request boundary).\n * - `adopted` — the marker is gone; the user replaced the file and owns it\n * now (mirrors `eject`, which preserves marker-less files).\n * - `managed` — marker present; used in template mode, where no recorded\n * hash exists to tell pristine from edited.\n * - `missing` — the file is gone. Infrastructure ⇒ fail, presentation ⇒ warn.\n */\ntype ScaffoldFileState = \"pristine\" | \"edited\" | \"adopted\" | \"managed\" | \"missing\";\n\ntype ScaffoldFileRow = {\n path: string;\n class: ScaffoldFileClass;\n state: ScaffoldFileState;\n};\n\n/**\n * Verifies the scaffolded app files still exist: the ones `zitadel setup`\n * wrote per the scaffold manifest in `.zitadel/state.json`, or — for apps\n * scaffolded before the manifest existed — the patcher's current template\n * expectations minus conditionally-written files. A missing *infrastructure*\n * file (request boundary, provider, type declarations) breaks the auth\n * integration and fails the check; a missing *presentation* page only warns.\n * Edited and user-adopted files pass — they are the intended customization\n * paths — and are labelled in `details` for visibility.\n *\n * Implements {@link SanityCheck} directly rather than via the abstract base:\n * the base's `verify`-throws contract can only express pass/fail, and this\n * check needs the `warn` outcome.\n */\nexport class ManagedFilesCheck implements SanityCheck {\n readonly name = \"managed-files\";\n\n async run(ctx: CheckContext): Promise<CheckOutcome> {\n const manifest = await readScaffoldManifest(ctx.cwd);\n const evaluated = manifest\n ? await evaluateManifest(ctx.cwd, manifest)\n : await evaluateTemplates(ctx);\n if (!evaluated) {\n return {\n name: this.name,\n status: \"warn\",\n message:\n \"Could not enumerate scaffolded app files (framework or renderer unresolved); skipping the file check\",\n };\n }\n\n const { mode, rows } = evaluated;\n const wiring = await probeConfigWiring(ctx);\n const actions = await resolveArtifacts(ctx);\n const boundaries = actions\n ? await detectBoundaryConflicts(actions, ctx.cwd, manifest)\n : [];\n const missing = rows.filter((row) => row.state === \"missing\");\n const missingInfrastructure = missing.filter((row) => row.class === \"infrastructure\");\n const detachedInfrastructure = wiring.filter(\n (s) => s.state === \"detached\" && s.wiring === \"infrastructure\",\n );\n const detachedConvenience = wiring.filter(\n (s) => s.state === \"detached\" && s.wiring === \"convenience\",\n );\n const unverifiable = wiring.filter((s) => s.state === \"unknown\");\n const conflicts = boundaries.filter((b) => b.disposition === \"conflict\");\n const removable = boundaries.filter((b) => b.disposition === \"removable\");\n const details = {\n mode,\n files: rows,\n ...(wiring.length > 0 ? { config_wiring: wiring } : {}),\n ...(boundaries.length > 0 ? { boundary_conflicts: boundaries } : {}),\n };\n\n const failures: string[] = [];\n if (missingInfrastructure.length > 0) {\n failures.push(\n `missing scaffolded infrastructure file(s): ${listPaths(missingInfrastructure)}`,\n );\n }\n if (detachedInfrastructure.length > 0) {\n failures.push(\n `detached managed config wiring: ${detachedInfrastructure\n .map((s) => s.path)\n .join(\", \")}`,\n );\n }\n for (const conflict of conflicts) {\n failures.push(\n `conflicting request boundaries: ${conflict.retired} is user-modified while the current templates use ${conflict.current} — migrate your changes and remove one of them manually`,\n );\n }\n if (failures.length > 0) {\n return { name: this.name, status: \"fail\", message: failures.join(\"; \"), details };\n }\n\n const warnings: string[] = [];\n if (missing.length > 0) {\n warnings.push(`missing scaffolded page(s): ${listPaths(missing)}`);\n }\n if (detachedConvenience.length > 0) {\n warnings.push(\n `unapplied managed config edit(s): ${detachedConvenience.map((s) => s.path).join(\", \")}`,\n );\n }\n if (unverifiable.length > 0) {\n warnings.push(\n `unverifiable managed config wiring (manual review required): ${unverifiable\n .map((s) => (s.reason ? `${s.path} (${s.reason})` : s.path))\n .join(\", \")}`,\n );\n }\n for (const leftover of removable) {\n warnings.push(\n `retired boundary ${leftover.retired} left over from a template migration (doctor --fix removes it and installs ${leftover.current})`,\n );\n }\n if (warnings.length > 0) {\n return { name: this.name, status: \"warn\", message: warnings.join(\"; \"), details };\n }\n\n return {\n name: this.name,\n status: \"pass\",\n message: `Scaffolded app files are present (${rows.length} tracked${\n wiring.length > 0 ? `, ${wiring.length} wiring${wiring.length === 1 ? \"\" : \"s\"} verified` : \"\"\n }${mode === \"template\" ? \", from templates\" : \"\"})`,\n details,\n };\n }\n\n /**\n * Restores missing managed files via the patcher's missing-only repair —\n * existing files, edited or adopted, are never overwritten — then refreshes\n * the manifest hashes of the files the repair brought back so they classify\n * as pristine again. The restored bytes come from the *current* templates,\n * which may differ from what the original CLI version wrote; the re-hash\n * records that honestly. On a pre-manifest app (template mode) a successful\n * repair also materializes the manifest from the marker-bearing files now\n * on disk, completing the migration ADR 042 promises — adopted files stay\n * the user's and are not recorded.\n */\n async fix(ctx: CheckContext): Promise<void> {\n const manifest = await readScaffoldManifest(ctx.cwd);\n const missingBefore = manifest ? await missingManifestPaths(ctx.cwd, manifest) : [];\n const patchCtx = await loadPatchContext(ctx.cwd, ctx.orca, ctx.cliVersion);\n const patcher = ctx.orca.patcherFor(patchCtx.framework.id);\n const actions = patcher.artifacts({\n framework: patchCtx.framework,\n rendererId: patchCtx.rendererId,\n });\n // Boundary migration: a *pristine* retired alternate (hash-proven CLI\n // bytes, e.g. Next 15's middleware.ts after an upgrade) is removed so the\n // current boundary can be installed without the framework rejecting the\n // pair. A user-modified or adopted alternate is a conflict: it stays, and\n // the current boundary is excluded from the repair — creating proxy.ts\n // beside an edited middleware.ts would break the build outright. Dry-run\n // deletes nothing and keeps the exclusion, so the preview stays safe.\n const boundaries = await detectBoundaryConflicts(actions, ctx.cwd, manifest);\n const excludePaths = boundaries\n .filter((b) => b.disposition === \"conflict\")\n .map((b) => b.current);\n const removed: string[] = [];\n if (!ctx.dryRun) {\n for (const boundary of boundaries) {\n if (boundary.disposition === \"removable\") {\n await rm(join(ctx.cwd, boundary.retired), { force: true });\n removed.push(boundary.retired);\n }\n }\n }\n await patcher.repair(patchCtx, {\n cwd: ctx.cwd,\n dryRun: ctx.dryRun,\n force: false,\n missingOnly: true,\n ...(excludePaths.length > 0 ? { excludePaths } : {}),\n });\n if (ctx.dryRun) {\n return;\n }\n if (!manifest) {\n await materializeManifest(ctx, patchCtx);\n return;\n }\n if (missingBefore.length === 0 && removed.length === 0) {\n return;\n }\n // Reconcile the manifest with the current template set before rewriting\n // it. Template migrations (Next 15's middleware.ts → Next 16's proxy.ts)\n // retire paths the current plan no longer writes: repair restores the\n // *new* boundary, so a retired entry whose file stays absent must be\n // dropped — keeping it would fail doctor forever, since setup skips\n // initialized projects. Paths the repair newly introduced are adopted\n // with their class and on-disk hash.\n const current = new Set(actions.markedFiles);\n const conditional = new Set(actions.conditionalFiles ?? []);\n const files: ScaffoldManifest[\"files\"] = {};\n for (const [path, entry] of Object.entries(manifest.files)) {\n const contents = await readIfExists(join(ctx.cwd, path));\n if (contents === undefined && !current.has(path)) {\n continue; // retired by a template migration and gone from disk\n }\n files[path] =\n contents !== undefined && missingBefore.includes(path)\n ? { ...entry, hash: hashScaffoldFile(contents) }\n : entry;\n }\n for (const path of actions.markedFiles) {\n if (files[path] || conditional.has(path)) {\n continue;\n }\n const contents = await readIfExists(join(ctx.cwd, path));\n if (contents !== undefined && contents.includes(MANAGED_MARKER)) {\n files[path] = {\n hash: hashScaffoldFile(contents),\n class: actions.fileClasses?.[path] ?? \"presentation\",\n };\n }\n }\n await updateScaffold(ctx.cwd, { ...manifest, files });\n }\n}\n\n/**\n * A retired template alternate (an old boundary filename) that still exists\n * beside — or instead of — the file the current templates write.\n * `removable`: hash-proven pristine CLI bytes per the manifest, safe for\n * `--fix` to delete during migration. `conflict`: user-modified, adopted, or\n * simply unhashable (template mode) — never deleted, and the current\n * counterpart must not be created next to it.\n */\ntype BoundaryConflict = {\n current: string;\n retired: string;\n disposition: \"removable\" | \"conflict\";\n};\n\nasync function detectBoundaryConflicts(\n actions: EjectActions,\n cwd: string,\n manifest: ScaffoldManifest | undefined,\n): Promise<BoundaryConflict[]> {\n const conflicts: BoundaryConflict[] = [];\n for (const [current, retiredPaths] of Object.entries(actions.retiredAlternates ?? {})) {\n for (const retired of retiredPaths) {\n const contents = await readIfExists(join(cwd, retired));\n if (contents === undefined) {\n continue;\n }\n const entry = manifest?.files[retired];\n const pristine =\n entry !== undefined &&\n contents.includes(MANAGED_MARKER) &&\n hashScaffoldFile(contents) === entry.hash;\n conflicts.push({ current, retired, disposition: pristine ? \"removable\" : \"conflict\" });\n }\n }\n return conflicts;\n}\n\n/**\n * Probe the patcher's managed config wirings (dev proxy merges, route\n * registrations). Needs the full patch context (project secret et al) to\n * rebuild the plan; when that fails — missing secret, undetectable\n * framework — the probe is skipped silently and the responsible check\n * reports the real problem.\n */\nasync function probeConfigWiring(\n ctx: CheckContext,\n): Promise<ReadonlyArray<ConfigWiringStatus>> {\n try {\n const patchCtx = await loadPatchContext(ctx.cwd, ctx.orca, ctx.cliVersion);\n return await ctx.orca\n .patcherFor(patchCtx.framework.id)\n .verify(patchCtx, { cwd: ctx.cwd });\n } catch {\n return [];\n }\n}\n\n/**\n * Migration path for apps scaffolded before the manifest existed: after a\n * template-mode repair, record the marker-bearing managed files now on disk\n * so the next doctor run gets exact manifest-mode verification instead of\n * template guessing (and its Next-major / template-growth misclassification\n * risk). Marker-less (adopted) files and conditionally-scaffolded ones are\n * deliberately absent.\n *\n * The manifest is only finalized when every current *infrastructure* file is\n * present and recordable (marker-bearing): materializing during an\n * unresolved boundary conflict — or over an adopted boundary — would write a\n * manifest that tracks no request boundary at all, and deleting the boundary\n * later would go undetected. Until then the app stays on the template\n * fallback, whose presence checks keep enforcing the boundary. Best-effort:\n * an unreadable state file leaves the app in template mode, same as before.\n */\nasync function materializeManifest(\n ctx: CheckContext,\n patchCtx: Awaited<ReturnType<typeof loadPatchContext>>,\n): Promise<void> {\n try {\n const actions = ctx.orca.patcherFor(patchCtx.framework.id).artifacts({\n framework: patchCtx.framework,\n rendererId: patchCtx.rendererId,\n });\n const conditional = new Set(actions.conditionalFiles ?? []);\n const marked: string[] = [];\n for (const path of actions.markedFiles) {\n if (conditional.has(path)) {\n continue;\n }\n const contents = await readIfExists(join(ctx.cwd, path));\n if (contents !== undefined && contents.includes(MANAGED_MARKER)) {\n marked.push(path);\n }\n }\n const infrastructure = actions.markedFiles.filter(\n (path) => actions.fileClasses?.[path] === \"infrastructure\" && !conditional.has(path),\n );\n if (!infrastructure.every((path) => marked.includes(path))) {\n return;\n }\n await writeScaffoldManifest({ cwd: ctx.cwd, actions, written: marked });\n } catch {\n // state.json unreadable or the write raced — stays in template mode.\n }\n}\n\nasync function evaluateManifest(\n cwd: string,\n manifest: ScaffoldManifest,\n): Promise<{ mode: \"manifest\"; rows: ScaffoldFileRow[] }> {\n const rows: ScaffoldFileRow[] = [];\n for (const [path, entry] of Object.entries(manifest.files)) {\n const contents = await readIfExists(join(cwd, path));\n rows.push({ path, class: entry.class, state: stateFor(contents, entry.hash) });\n }\n return { mode: \"manifest\", rows };\n}\n\n/**\n * Fallback for apps scaffolded before the manifest existed: derive the\n * expected set from the patcher's current templates. Conditionally-written\n * files (e.g. the framework home page) are excluded — without a manifest\n * there is no way to know whether setup ever wrote them. Presence-only:\n * no recorded hash means `pristine` vs `edited` cannot be told apart.\n */\nasync function evaluateTemplates(\n ctx: CheckContext,\n): Promise<{ mode: \"template\"; rows: ScaffoldFileRow[] } | undefined> {\n const actions = await resolveArtifacts(ctx);\n if (!actions) {\n return undefined;\n }\n const conditional = new Set(actions.conditionalFiles ?? []);\n const rows: ScaffoldFileRow[] = [];\n for (const path of actions.markedFiles) {\n if (conditional.has(path)) {\n continue;\n }\n const contents = await readIfExists(join(ctx.cwd, path));\n rows.push({\n path,\n class: actions.fileClasses?.[path] ?? \"presentation\",\n state: stateFor(contents, undefined),\n });\n }\n return { mode: \"template\", rows };\n}\n\n/**\n * Resolves the patcher artifacts the same way `eject` does, tolerating every\n * failure with `undefined`: a broken framework detection, an unreadable\n * config, or an unresolvable renderer are reported by their own checks —\n * this one only degrades to \"cannot enumerate\".\n */\nasync function resolveArtifacts(ctx: CheckContext): Promise<EjectActions | undefined> {\n const framework = await ctx.orca.tryDetect(ctx.cwd);\n if (!framework) {\n return undefined;\n }\n try {\n const config = await readZitadelConfig(ctx.cwd).catch(() => ({}) as Record<string, unknown>);\n return ctx.orca.patcherFor(framework.id).artifacts({\n framework,\n rendererId: readRendererId(config),\n });\n } catch {\n return undefined;\n }\n}\n\nfunction stateFor(contents: string | undefined, hash: string | undefined): ScaffoldFileState {\n if (contents === undefined) {\n return \"missing\";\n }\n if (!contents.includes(MANAGED_MARKER)) {\n return \"adopted\";\n }\n if (hash === undefined) {\n return \"managed\";\n }\n return hashScaffoldFile(contents) === hash ? \"pristine\" : \"edited\";\n}\n\nasync function missingManifestPaths(cwd: string, manifest: ScaffoldManifest): Promise<string[]> {\n const missing: string[] = [];\n for (const path of Object.keys(manifest.files)) {\n if ((await readIfExists(join(cwd, path))) === undefined) {\n missing.push(path);\n }\n }\n return missing;\n}\n\nasync function readIfExists(path: string): Promise<string | undefined> {\n try {\n return await readFile(path, \"utf8\");\n } catch {\n return undefined;\n }\n}\n\nfunction listPaths(rows: ReadonlyArray<ScaffoldFileRow>): string {\n return rows.map((row) => row.path).join(\", \");\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","import { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { ZitadelError } from \"./errors\";\n\n/**\n * Read every `*.json` file under `absDir` and return each body as a plain\n * object. Files are read in lexical filename order so the result is\n * deterministic for downstream hashing and diffs. Each file is parsed by\n * `JSON.parse`; this function does **not** apply any schema validation —\n * unknown keys, forward-compatible fields, and `${VAR}` placeholders survive\n * intact. Callers that need a typed shape pass the result through their\n * resource's Zod schema.\n *\n * Returns an empty array when the directory is missing. Throws `E_VALIDATION`\n * `ZitadelError` on invalid JSON or when a file's root value is not an object.\n *\n * @param absDir - Absolute path to the directory to scan.\n */\nexport async function readJsonDir(absDir: string): Promise<ReadonlyArray<Record<string, unknown>>> {\n let entries: string[];\n try {\n entries = await readdir(absDir);\n } catch (error) {\n if (typeof error === \"object\" && error !== null && \"code\" in error && error.code === \"ENOENT\") {\n return [];\n }\n throw error;\n }\n const result: Record<string, unknown>[] = [];\n for (const entry of entries.filter((name) => name.endsWith(\".json\")).sort()) {\n const abs = join(absDir, entry);\n let raw: unknown;\n try {\n raw = JSON.parse(await readFile(abs, \"utf8\"));\n } catch {\n throw new ZitadelError(\"E_VALIDATION\", `${entry} is not valid JSON`);\n }\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n throw new ZitadelError(\"E_VALIDATION\", `${entry} must contain a JSON object at the root`);\n }\n result.push(raw as Record<string, unknown>);\n }\n return result;\n}\n","import { join } from \"node:path\";\n\nimport { schemaConfigSchema } from \"@zitadel/config/schemas\";\n\nimport { readJsonDir } from \"../../../lib/json-dir\";\nimport { SCHEMAS_DIR } from \"../../../lib/user-schema\";\nimport { AbstractSanityCheck, type CheckContext, type CheckOutcome } from \"./types\";\n\n/**\n * Verifies local schema config files round-trip through the canonical\n * `schemaConfigSchema` from `@zitadel/config/schemas` — the same Zod the\n * sync engine validates with, so doctor and `apply` can never disagree\n * about a file. The union enforces the `kind` discriminator\n * (`user-schema` / `schema-url`) and the `metaSchema`/`x-auth-methods`/etc.\n * fields the platform requires.\n */\nexport class SchemaCheck extends AbstractSanityCheck {\n readonly name = \"schema\";\n readonly path = SCHEMAS_DIR;\n protected readonly summary = \"User schemas are valid Zitadel schema bodies\";\n\n /**\n * An empty `.zitadel/schemas/` is a warning, not a failure: projects\n * created before editable config existed were seeded server-side and have\n * no local schema files, and there is no safe auto-fix that could invent\n * them. Only invalid files fail the check.\n */\n override async run(ctx: CheckContext): Promise<CheckOutcome> {\n const schemas = await readJsonDir(join(ctx.cwd, SCHEMAS_DIR));\n if (schemas.length === 0) {\n return {\n name: this.name,\n status: \"warn\",\n message:\n `No schema files found in ${SCHEMAS_DIR} — this project predates editable ` +\n \"schema config or setup was interrupted. New projects scaffold editable \" +\n \"defaults via `zitadel setup`.\",\n path: this.path,\n };\n }\n return super.run(ctx);\n }\n\n protected async verify(ctx: CheckContext): Promise<void> {\n const schemas = await readJsonDir(join(ctx.cwd, SCHEMAS_DIR));\n for (const schema of schemas) {\n const result = schemaConfigSchema.safeParse(schema);\n if (!result.success) {\n throw new Error(\n result.error.issues\n .map((issue) => `${issue.path.join(\".\") || \"/\"} ${issue.message}`)\n .join(\"; \"),\n );\n }\n }\n }\n}\n","import { claimState, type ClaimState } from \"../../../lib/claim-state\";\nimport { readProjectServer, readZitadelConfig, readZitadelSecret } from \"../../../lib/project\";\nimport type { CheckContext, CheckOutcome, SanityCheck } from \"./types\";\n\n/**\n * Reports whether the project is attached to a team, reading `claimed_at` and\n * `team_id` from `.zitadel/secret`.\n *\n * Always advisory, never a failure. An unattached project works exactly like an\n * attached one — same issuer, same users, same applications — so the only thing\n * missing is durability, which is the developer's call and not a defect. That\n * matters mechanically too: `doctor` turns any `fail` into a thrown\n * `E_VALIDATION`, so failing here would break every scripted `zitadel doctor`\n * against a project nobody had claimed yet.\n *\n * Implements {@link SanityCheck} directly rather than via the abstract base,\n * for the same reason `ManagedFilesCheck` does: the base's `verify`-throws\n * contract can only express pass/fail, and this check is only ever warn or\n * pass.\n */\nexport class ClaimCheck implements SanityCheck {\n readonly name = \"claim\";\n readonly path = \".zitadel/secret\";\n\n async run(ctx: CheckContext): Promise<CheckOutcome> {\n let state: ClaimState;\n try {\n state = claimState({\n secret: await readZitadelSecret(ctx.cwd),\n // From `zitadel.json`, not the command's own source: `doctor` pins its\n // source to the local runtime URL, so asking it where the project lives\n // would report every project as local.\n server: readProjectServer(await readZitadelConfig(ctx.cwd)),\n });\n } catch {\n // A missing or unparseable secret/config is already reported, loudly and\n // with a repair path, by the `secret` and `config` checks. Implementing\n // `SanityCheck` directly means nothing wraps a throw here, so swallowing\n // it is what keeps a broken project reporting its real problem instead of\n // crashing the whole battery on a nudge.\n return {\n name: this.name,\n status: \"pass\",\n message: \"Skipped: could not read the project files that record the owning team\",\n path: this.path,\n };\n }\n\n if (state.kind === \"detached\") {\n return {\n name: this.name,\n status: \"warn\",\n message:\n \"This project is temporary until you attach it to a team. Run `zitadel claim` \" +\n \"to make it permanent; nothing about the project changes.\",\n path: this.path,\n };\n }\n\n return {\n name: this.name,\n status: \"pass\",\n message:\n state.kind === \"attached\"\n ? `Project is attached to team ${state.team_id}`\n : // Local and self-hosted servers have no team to attach to, so the\n // check passes rather than warning about an impossible action.\n \"Project is not on a server where teams apply\",\n path: this.path,\n };\n }\n\n /**\n * Deliberately a no-op. `doctor --fix` calls `fix` on every non-passing\n * check, but claiming requires a human to sign in through a browser, so there\n * is nothing safe to automate here.\n */\n async fix(_ctx: CheckContext): Promise<void> {\n return;\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 { DependencyVersionCheck } from \"./dependency-version\";\nimport { ManagedFilesCheck } from \"./managed-files\";\nimport { ProjectMatchCheck } from \"./project-match\";\nimport { SchemaCheck } from \"./schema\";\nimport { ClaimCheck } from \"./claim\";\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 { DependencyVersionCheck } from \"./dependency-version\";\nexport { ManagedFilesCheck } from \"./managed-files\";\nexport { ProjectMatchCheck } from \"./project-match\";\nexport { ClaimCheck } from \"./claim\";\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 new SchemaCheck(),\n new DependencyCheck(),\n new DependencyVersionCheck(),\n new ManagedFilesCheck(),\n new ProjectMatchCheck(),\n new ClaimCheck(),\n];\n","import { Flags } from \"@oclif/core\";\nimport consola from \"consola\";\n\nimport { claimAction, claimCommand } from \"../../lib/claim-state\";\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 discoverManagedRuntimeProcesses,\n type ManagedRuntimeProcess,\n} from \"../../lib/local-server/processes\";\nimport {\n DEFAULT_LOCAL_SERVER_PORT,\n assertLocalStateWritable,\n checkLocalServerHealth,\n defaultLocalServerImageForCliVersion,\n localServerUrl,\n readRuntimeMetadata,\n type RuntimeBackend,\n type RuntimeMetadata,\n} from \"../../lib/local-server/runtime\";\nimport { BaseCommand, type JsonEnvelope } from \"../../lib/oclif\";\nimport { createOrca } from \"../../lib/orca\";\nimport { hasZitadelConfig } from \"../../lib/project\";\nimport { listenersForPort } from \"../../lib/prober/ports\";\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 check that did not pass — failed or warned —\n * first attempts its own repair (a no-op for checks with no safe automatic\n * 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: \"Repair missing files and stale managed wiring.\" }),\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 // Repair warn-level drift too (e.g. a deleted presentation page):\n // fixes are restore-missing-only, so running one on a warning is safe.\n if (before[index]?.status === \"pass\") {\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 this.recordTelemetry({\n runtime: runtimeBackend,\n checks_total: checks.length,\n checks_failed: failed.length,\n checks_warn: warnings.length,\n failed_checks: failed.length > 0 ? failed.map((check) => check.name).join(\",\") : undefined,\n });\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 // A check that failed with a typed CLI error advertises its own\n // category (e.g. the framework floor's E_UNSUPPORTED_PROJECT_SHAPE) —\n // surface that instead of the generic validation class so agents can\n // branch on it. The port check keeps its dedicated code first.\n const code = failed.some((check) => check.name === \"port\")\n ? \"E_PORT_IN_USE\"\n : (failed.find((check) => check.code !== undefined)?.code ?? \"E_VALIDATION\");\n throw new ZitadelError(code, \"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 const stopCommand = publicCliCommand(\"stop --all\", cliVersion);\n const retryCommand = publicCliCommand(\"doctor\", cliVersion);\n const alternatePortCommand = publicCliCommand(\n `doctor --port ${String(fallbackPort)}`,\n cliVersion,\n );\n return {\n hint:\n `Port ${String(port)} is already in use. Stop the process using it, ` +\n `run \\`${stopCommand}\\` for CLI-managed local runtimes, then rerun ` +\n `\\`${retryCommand}\\`; or choose another port with \\`${alternatePortCommand}\\`.`,\n nextCommands: [stopCommand, retryCommand, alternatePortCommand],\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 // A failure that surfaced as a typed CLI error carries its own remedy —\n // e.g. the framework floor's upgrade hint. That beats the generic --fix\n // advice below, which cannot repair an unsupported version.\n const typed = failed.find((check) => check.code !== undefined && check.hint !== undefined);\n if (typed?.hint !== undefined) {\n return { hint: typed.hint, nextCommands: [publicCliCommand(\"doctor\", cliVersion)] };\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 const nextActions: string[] = [];\n const nextCommands: string[] = [];\n if (warnings.some((check) => check.name === \"docker-cli\")) {\n const advice = dockerRuntimeGuidance(\"doctor\", cliVersion);\n nextActions.push(...advice.nextActions);\n nextCommands.push(...advice.nextCommands);\n }\n\n if (warnings.some((check) => check.name === \"claim\")) {\n nextActions.push(claimAction(cliVersion));\n nextCommands.push(claimCommand(cliVersion));\n }\n\n const managedRuntimeWarning = warnings.find((check) => check.name === \"managed-runtime-processes\");\n if (hasManagedRuntimeProcesses(managedRuntimeWarning)) {\n nextActions.push(\n \"Review other host-wide CLI-managed local Zitadel runtimes before starting a new one.\",\n );\n nextCommands.push(publicCliCommand(\"stop --all\", cliVersion));\n }\n\n if (nextActions.length === 0 && nextCommands.length === 0) {\n return undefined;\n }\n return { nextActions: unique(nextActions), nextCommands: unique(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 const managedRuntimeCheck = await checkManagedRuntimeProcesses(runtime);\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 () => checkPortAvailability(runtime, port),\n ),\n await checkRuntime(runtime, runtimeBackend),\n managedRuntimeCheck,\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 () => checkPortAvailability(runtime, port),\n ),\n await checkRuntime(runtime, runtimeBackend),\n managedRuntimeCheck,\n ];\n}\n\nasync function checkPortAvailability(\n runtime: RuntimeMetadata | undefined,\n port: number,\n): Promise<string> {\n if (runtime?.port === port && (await checkLocalServerHealth(runtime.server_url))) {\n return `${runtime.server_url} is already healthy`;\n }\n const listeners = await listenersForPort(port);\n if (listeners.length > 0) {\n throw new PortInUseCheckError(port, localServerUrl(port), listeners);\n }\n return `Port ${String(port)} is available`;\n}\n\nclass PortInUseCheckError extends Error {\n constructor(\n readonly port: number,\n readonly serverUrl: string,\n readonly listeners: Awaited<ReturnType<typeof listenersForPort>>,\n ) {\n super(`Port ${String(port)} is already in use by ${formatListeners(listeners)}`);\n }\n}\n\nasync function checkManagedRuntimeProcesses(\n runtime: RuntimeMetadata | undefined,\n): Promise<CheckOutcome> {\n const discovery = await discoverManagedRuntimeProcesses();\n if (!discovery.supported) {\n return {\n name: \"managed-runtime-processes\",\n status: \"warn\",\n message: \"Managed local runtime process discovery is unavailable.\",\n details: { supported: false, error: discovery.error },\n };\n }\n const processes = additionalManagedRuntimeProcesses(discovery.processes, runtime);\n if (processes.length === 0) {\n return {\n name: \"managed-runtime-processes\",\n status: \"pass\",\n message: \"No additional host-wide managed local runtime processes found.\",\n details: { supported: true, scope: \"host\", processes: [] },\n };\n }\n return {\n name: \"managed-runtime-processes\",\n status: \"warn\",\n message: `${String(processes.length)} other host-wide managed local runtime process${processes.length === 1 ? \"\" : \"es\"} found.`,\n details: { supported: true, scope: \"host\", processes },\n };\n}\n\nfunction additionalManagedRuntimeProcesses(\n processes: ReadonlyArray<ManagedRuntimeProcess>,\n runtime: RuntimeMetadata | undefined,\n): ReadonlyArray<ManagedRuntimeProcess> {\n if (runtime?.backend !== \"binary\") {\n return processes;\n }\n return processes.filter((processInfo) => processInfo.pid !== runtime.pid && processInfo.ppid !== runtime.pid);\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 formatListeners(listeners: Awaited<ReturnType<typeof listenersForPort>>): string {\n return listeners\n .map((listener) =>\n [listener.command ?? \"unknown\", listener.pid ? `pid ${String(listener.pid)}` : undefined]\n .filter(Boolean)\n .join(\" \"),\n )\n .join(\", \");\n}\n\nfunction hasManagedRuntimeProcesses(check: CheckOutcome | undefined): boolean {\n if (!check || check.status !== \"warn\") {\n return false;\n }\n const details = check.details;\n return (\n typeof details === \"object\" &&\n details !== null &&\n \"supported\" in details &&\n (details as { supported?: unknown }).supported === true &&\n Array.isArray((details as { processes?: unknown }).processes) &&\n ((details as { processes?: unknown[] }).processes?.length ?? 0) > 0\n );\n}\n\nfunction unique(values: string[]): string[] {\n return [...new Set(values)];\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 if (error instanceof PortInUseCheckError) {\n return {\n name,\n status: failureStatus,\n message: error.message,\n details: {\n port: error.port,\n server_url: error.serverUrl,\n listeners: error.listeners,\n },\n };\n }\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
+ {"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/dependency-version.ts","../../src/commands/doctor/checks/managed-files.ts","../../src/commands/doctor/checks/project-match.ts","../../src/lib/json-dir.ts","../../src/commands/doctor/checks/schema.ts","../../src/commands/doctor/checks/claim.ts","../../src/commands/doctor/checks/index.ts","../../src/commands/doctor/index.ts"],"sourcesContent":["import { ZitadelError, type ZitadelErrorCode } from \"../../../lib/errors\";\nimport type { Orca } from \"../../../lib/orca\";\n\n/** Pass/fail/advisory outcome of a single {@link SanityCheck}. */\nexport type CheckOutcome = {\n details?: unknown;\n name: string;\n status: \"pass\" | \"warn\" | \"fail\";\n message: string;\n path?: string;\n /**\n * Set when the failure surfaced as a typed CLI error: the error's category\n * and remedy travel through the outcome so the doctor envelope can carry\n * the advertised code (e.g. the framework floor's\n * `E_UNSUPPORTED_PROJECT_SHAPE`) and hint instead of generic advice.\n */\n code?: ZitadelErrorCode;\n hint?: 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 ...(error instanceof ZitadelError\n ? { code: error.code, ...(error.hint === undefined ? {} : { hint: error.hint }) }\n : {}),\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 { issuerFromPort, type FrameworkFacts, type Orca } from \"../../lib/orca\";\nimport type { PatchContext } from \"../../lib/orca/patchers/types\";\nimport {\n readDevelopmentIssuer,\n readPreset,\n readRendererId,\n readUseCase,\n readZitadelConfig,\n readZitadelSecret,\n} from \"../../lib/project\";\nimport { readScaffoldManifest } from \"../../lib/scaffold-manifest\";\n\n/**\n * Reconstructs a {@link PatchContext} from the on-disk project (config,\n * secret, scaffold manifest) plus fresh framework detection, so a patcher\n * repair can rebuild its plan. Used by the doctor checks' `fix` paths.\n * `preset`/`useCase` come back from `zitadel.json` and\n * `scaffoldedFramework` from the scaffold manifest, so the rebuilt plan\n * matches what setup originally emitted (a fresh-scaffolded app's home page\n * is part of the plan again, for example). Schema and flow config are\n * user-editable sync resources, not patcher inputs, so nothing here reads\n * 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 const scaffold = await readScaffoldManifest(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 scaffoldedFramework: scaffold?.scaffolded_framework,\n // Restore the posture setup recorded rather than re-deriving it — a\n // manifest-less legacy scaffold cannot answer the fresh-vs-pre-existing\n // hinge, and every scaffold before the record was full-page (ADR 044).\n posture: scaffold?.posture ?? \"page\",\n preset: readPreset(config),\n useCase: readUseCase(config),\n project: {\n id: secret.project_id,\n project_secret: secret.project_secret,\n preview_secret: secret.preview_secret,\n preview_origins: secret.preview_origins,\n created_at: 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 scaffold = await readScaffoldManifest(cwd);\n if (typeof scaffold?.dev_port === \"number\") {\n return issuerFromPort(scaffold.dev_port);\n }\n return facts.url;\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 re-applying 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. Missing-only:\n * the repair restores absent managed files as a side effect but never\n * overwrites an existing one, edited or not.\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: false,\n missingOnly: true,\n });\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport semver from \"semver\";\n\nimport { addExactCommandFor, detectPackageManager } from \"../../../lib/package-manager\";\nimport type { CheckContext, CheckOutcome, SanityCheck } from \"./types\";\n\n/**\n * Verifies that exactly-pinned `@zitadel/*` dependencies match this CLI's own\n * version. The packages publish as one lockstep train, and the scaffold pins\n * the SDK at the CLI's version — but the CLI floats (`npx @zitadel/cli@alpha`)\n * while the app's pin stays put, so a newer CLI can restore files or write\n * guidance that references SDK entry points the older pinned SDK does not\n * ship (e.g. a subpath export added a train later). A mismatch therefore\n * *warns* with the exact remedy instead of leaving the skew to surface as a\n * module-not-found in the app.\n *\n * Only exact semver pins are compared: ranges, dist-tags, and `file:`/\n * `workspace:` specifiers express a deliberate resolution choice the check\n * cannot second-guess.\n *\n * Implements {@link SanityCheck} directly: the abstract base's verify-throws\n * contract can only express pass/fail, and a version skew is advisory — the\n * app keeps working on its pinned train until the user upgrades.\n */\nexport class DependencyVersionCheck implements SanityCheck {\n readonly name = \"dependency-version\";\n readonly path = \"package.json\";\n\n async run(ctx: CheckContext): Promise<CheckOutcome> {\n const base = { name: this.name, path: this.path };\n if (semver.valid(ctx.cliVersion) === null) {\n // A dev or placeholder CLI version has no train to compare against.\n return {\n ...base,\n status: \"pass\",\n message: `CLI version ${ctx.cliVersion} is not an exact release; skipping the pin comparison`,\n };\n }\n let pkg: { dependencies?: Record<string, string>; devDependencies?: Record<string, string> };\n try {\n pkg = JSON.parse(await readFile(join(ctx.cwd, \"package.json\"), \"utf8\")) as typeof pkg;\n } catch {\n // A missing or unparsable package.json is the dependency check's\n // failure to report; double-flagging the same root cause helps nobody.\n return { ...base, status: \"pass\", message: \"no package.json to compare pins against\" };\n }\n const declared = Object.entries({\n ...(pkg.dependencies ?? {}),\n ...(pkg.devDependencies ?? {}),\n }).filter(([name]) => name.startsWith(\"@zitadel/\"));\n const exact = declared.filter(([, version]) => semver.valid(version.trim()) !== null);\n const mismatched = exact.filter(\n ([, version]) => !semver.eq(version.trim(), ctx.cliVersion),\n );\n if (mismatched.length > 0) {\n // Repair with the project's own package manager and an exact-save flag:\n // a bare `npm install` would switch managers on a pnpm/yarn/bun project\n // and write a caret range — exactly the float this check ignores.\n const remedy = addExactCommandFor(\n await detectPackageManager(ctx.cwd),\n mismatched.map(([name]) => `${name}@${ctx.cliVersion}`),\n ).display;\n return {\n ...base,\n status: \"warn\",\n message:\n `${mismatched.map(([name, version]) => `${name}@${version}`).join(\", \")} ` +\n `does not match this CLI's version (${ctx.cliVersion}); scaffolded files and ` +\n `guidance target the CLI's train — update with \\`${remedy}\\``,\n details: {\n mismatched: mismatched.map(([name, version]) => ({\n name,\n declared: version,\n expected: ctx.cliVersion,\n })),\n remedy_command: remedy,\n },\n };\n }\n return {\n ...base,\n status: \"pass\",\n message:\n exact.length > 0\n ? `Zitadel package pins match the CLI version (${exact.length} compared)`\n : \"no exactly-pinned Zitadel packages to compare\",\n };\n }\n\n /**\n * No auto-fix: repair's dependency op is deliberately additive-only (it\n * never rewrites a version the user declared), so the repair ships as the\n * package-manager-aware install command in `details.remedy_command` — the\n * doctor command surfaces it in the envelope's `next_commands` — with the\n * same command quoted in the warn message for human readers.\n */\n async fix(_ctx: CheckContext): Promise<void> {\n return;\n }\n}\n","import { readFile, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport type { ConfigWiringStatus, EjectActions } from \"../../../lib/orca/patchers/types\";\nimport { MANAGED_MARKER } from \"../../../lib/paths\";\nimport { readRendererId, readZitadelConfig } from \"../../../lib/project\";\nimport {\n hashScaffoldFile,\n readScaffoldManifest,\n writeScaffoldManifest,\n} from \"../../../lib/scaffold-manifest\";\nimport { updateScaffold } from \"../../../lib/sync/state\";\nimport type { ScaffoldFileClass, ScaffoldManifest } from \"../../../lib/sync/types\";\nimport { loadPatchContext } from \"../patch-context\";\nimport type { CheckContext, CheckOutcome, SanityCheck } from \"./types\";\n\n/**\n * Per-file classification reported in the check's `details`:\n *\n * - `pristine` — still the bytes setup wrote (manifest hash matches).\n * - `edited` — carries the managed marker but the content changed; the user\n * extended a managed file (e.g. added routes to the request boundary).\n * - `adopted` — the marker is gone; the user replaced the file and owns it\n * now (mirrors `eject`, which preserves marker-less files).\n * - `managed` — marker present; used in template mode, where no recorded\n * hash exists to tell pristine from edited.\n * - `missing` — the file is gone. Infrastructure ⇒ fail, presentation ⇒ warn.\n */\ntype ScaffoldFileState = \"pristine\" | \"edited\" | \"adopted\" | \"managed\" | \"missing\";\n\ntype ScaffoldFileRow = {\n path: string;\n class: ScaffoldFileClass;\n state: ScaffoldFileState;\n};\n\n/**\n * Verifies the scaffolded app files still exist: the ones `zitadel setup`\n * wrote per the scaffold manifest in `.zitadel/state.json`, or — for apps\n * scaffolded before the manifest existed — the patcher's current template\n * expectations minus conditionally-written files. A missing *infrastructure*\n * file (request boundary, provider, type declarations) breaks the auth\n * integration and fails the check; a missing *presentation* page only warns.\n * Edited and user-adopted files pass — they are the intended customization\n * paths — and are labelled in `details` for visibility.\n *\n * Implements {@link SanityCheck} directly rather than via the abstract base:\n * the base's `verify`-throws contract can only express pass/fail, and this\n * check needs the `warn` outcome.\n */\nexport class ManagedFilesCheck implements SanityCheck {\n readonly name = \"managed-files\";\n\n async run(ctx: CheckContext): Promise<CheckOutcome> {\n const manifest = await readScaffoldManifest(ctx.cwd);\n const evaluated = manifest\n ? await evaluateManifest(ctx.cwd, manifest)\n : await evaluateTemplates(ctx);\n if (!evaluated) {\n return {\n name: this.name,\n status: \"warn\",\n message:\n \"Could not enumerate scaffolded app files (framework or renderer unresolved); skipping the file check\",\n };\n }\n\n const { mode, rows } = evaluated;\n const wiring = await probeConfigWiring(ctx);\n const actions = await resolveArtifacts(ctx);\n const boundaries = actions\n ? await detectBoundaryConflicts(actions, ctx.cwd, manifest)\n : [];\n const missing = rows.filter((row) => row.state === \"missing\");\n const missingInfrastructure = missing.filter((row) => row.class === \"infrastructure\");\n const detachedInfrastructure = wiring.filter(\n (s) => s.state === \"detached\" && s.wiring === \"infrastructure\",\n );\n const detachedConvenience = wiring.filter(\n (s) => s.state === \"detached\" && s.wiring === \"convenience\",\n );\n const unverifiable = wiring.filter((s) => s.state === \"unknown\");\n const conflicts = boundaries.filter((b) => b.disposition === \"conflict\");\n const removable = boundaries.filter((b) => b.disposition === \"removable\");\n const details = {\n mode,\n files: rows,\n ...(wiring.length > 0 ? { config_wiring: wiring } : {}),\n ...(boundaries.length > 0 ? { boundary_conflicts: boundaries } : {}),\n };\n\n const failures: string[] = [];\n if (missingInfrastructure.length > 0) {\n failures.push(\n `missing scaffolded infrastructure file(s): ${listPaths(missingInfrastructure)}`,\n );\n }\n if (detachedInfrastructure.length > 0) {\n failures.push(\n `detached managed config wiring: ${detachedInfrastructure\n .map((s) => s.path)\n .join(\", \")}`,\n );\n }\n for (const conflict of conflicts) {\n failures.push(\n `conflicting request boundaries: ${conflict.retired} is user-modified while the current templates use ${conflict.current} — migrate your changes and remove one of them manually`,\n );\n }\n if (failures.length > 0) {\n return { name: this.name, status: \"fail\", message: failures.join(\"; \"), details };\n }\n\n const warnings: string[] = [];\n if (missing.length > 0) {\n warnings.push(`missing scaffolded page(s): ${listPaths(missing)}`);\n }\n if (detachedConvenience.length > 0) {\n warnings.push(\n `unapplied managed config edit(s): ${detachedConvenience.map((s) => s.path).join(\", \")}`,\n );\n }\n if (unverifiable.length > 0) {\n warnings.push(\n `unverifiable managed config wiring (manual review required): ${unverifiable\n .map((s) => (s.reason ? `${s.path} (${s.reason})` : s.path))\n .join(\", \")}`,\n );\n }\n for (const leftover of removable) {\n warnings.push(\n `retired boundary ${leftover.retired} left over from a template migration (doctor --fix removes it and installs ${leftover.current})`,\n );\n }\n if (warnings.length > 0) {\n return { name: this.name, status: \"warn\", message: warnings.join(\"; \"), details };\n }\n\n return {\n name: this.name,\n status: \"pass\",\n message: `Scaffolded app files are present (${rows.length} tracked${\n wiring.length > 0 ? `, ${wiring.length} wiring${wiring.length === 1 ? \"\" : \"s\"} verified` : \"\"\n }${mode === \"template\" ? \", from templates\" : \"\"})`,\n details,\n };\n }\n\n /**\n * Restores missing managed files via the patcher's missing-only repair —\n * existing files, edited or adopted, are never overwritten — then refreshes\n * the manifest hashes of the files the repair brought back so they classify\n * as pristine again. The restored bytes come from the *current* templates,\n * which may differ from what the original CLI version wrote; the re-hash\n * records that honestly. On a pre-manifest app (template mode) a successful\n * repair also materializes the manifest from the marker-bearing files now\n * on disk, completing the migration ADR 042 promises — adopted files stay\n * the user's and are not recorded.\n */\n async fix(ctx: CheckContext): Promise<void> {\n const manifest = await readScaffoldManifest(ctx.cwd);\n const missingBefore = manifest ? await missingManifestPaths(ctx.cwd, manifest) : [];\n const patchCtx = await loadPatchContext(ctx.cwd, ctx.orca, ctx.cliVersion);\n const patcher = ctx.orca.patcherFor(patchCtx.framework.id);\n const actions = patcher.artifacts({\n framework: patchCtx.framework,\n rendererId: patchCtx.rendererId,\n });\n // Boundary migration: a *pristine* retired alternate (hash-proven CLI\n // bytes, e.g. Next 15's middleware.ts after an upgrade) is removed so the\n // current boundary can be installed without the framework rejecting the\n // pair. A user-modified or adopted alternate is a conflict: it stays, and\n // the current boundary is excluded from the repair — creating proxy.ts\n // beside an edited middleware.ts would break the build outright. Dry-run\n // deletes nothing and keeps the exclusion, so the preview stays safe.\n const boundaries = await detectBoundaryConflicts(actions, ctx.cwd, manifest);\n const excludePaths = boundaries\n .filter((b) => b.disposition === \"conflict\")\n .map((b) => b.current);\n const removed: string[] = [];\n if (!ctx.dryRun) {\n for (const boundary of boundaries) {\n if (boundary.disposition === \"removable\") {\n await rm(join(ctx.cwd, boundary.retired), { force: true });\n removed.push(boundary.retired);\n }\n }\n }\n await patcher.repair(patchCtx, {\n cwd: ctx.cwd,\n dryRun: ctx.dryRun,\n force: false,\n missingOnly: true,\n ...(excludePaths.length > 0 ? { excludePaths } : {}),\n });\n if (ctx.dryRun) {\n return;\n }\n if (!manifest) {\n await materializeManifest(ctx, patchCtx);\n return;\n }\n if (missingBefore.length === 0 && removed.length === 0) {\n return;\n }\n // Reconcile the manifest with the current template set before rewriting\n // it. Template migrations (Next 15's middleware.ts → Next 16's proxy.ts)\n // retire paths the current plan no longer writes: repair restores the\n // *new* boundary, so a retired entry whose file stays absent must be\n // dropped — keeping it would fail doctor forever, since setup skips\n // initialized projects. Paths the repair newly introduced are adopted\n // with their class and on-disk hash.\n const current = new Set(actions.markedFiles);\n const conditional = new Set(actions.conditionalFiles ?? []);\n const files: ScaffoldManifest[\"files\"] = {};\n for (const [path, entry] of Object.entries(manifest.files)) {\n const contents = await readIfExists(join(ctx.cwd, path));\n if (contents === undefined && !current.has(path)) {\n continue; // retired by a template migration and gone from disk\n }\n files[path] =\n contents !== undefined && missingBefore.includes(path)\n ? { ...entry, hash: hashScaffoldFile(contents) }\n : entry;\n }\n for (const path of actions.markedFiles) {\n if (files[path] || conditional.has(path)) {\n continue;\n }\n const contents = await readIfExists(join(ctx.cwd, path));\n if (contents !== undefined && contents.includes(MANAGED_MARKER)) {\n files[path] = {\n hash: hashScaffoldFile(contents),\n class: actions.fileClasses?.[path] ?? \"presentation\",\n };\n }\n }\n await updateScaffold(ctx.cwd, { ...manifest, files });\n }\n}\n\n/**\n * A retired template alternate (an old boundary filename) that still exists\n * beside — or instead of — the file the current templates write.\n * `removable`: hash-proven pristine CLI bytes per the manifest, safe for\n * `--fix` to delete during migration. `conflict`: user-modified, adopted, or\n * simply unhashable (template mode) — never deleted, and the current\n * counterpart must not be created next to it.\n */\ntype BoundaryConflict = {\n current: string;\n retired: string;\n disposition: \"removable\" | \"conflict\";\n};\n\nasync function detectBoundaryConflicts(\n actions: EjectActions,\n cwd: string,\n manifest: ScaffoldManifest | undefined,\n): Promise<BoundaryConflict[]> {\n const conflicts: BoundaryConflict[] = [];\n for (const [current, retiredPaths] of Object.entries(actions.retiredAlternates ?? {})) {\n for (const retired of retiredPaths) {\n const contents = await readIfExists(join(cwd, retired));\n if (contents === undefined) {\n continue;\n }\n const entry = manifest?.files[retired];\n const pristine =\n entry !== undefined &&\n contents.includes(MANAGED_MARKER) &&\n hashScaffoldFile(contents) === entry.hash;\n conflicts.push({ current, retired, disposition: pristine ? \"removable\" : \"conflict\" });\n }\n }\n return conflicts;\n}\n\n/**\n * Probe the patcher's managed config wirings (dev proxy merges, route\n * registrations). Needs the full patch context (project secret et al) to\n * rebuild the plan; when that fails — missing secret, undetectable\n * framework — the probe is skipped silently and the responsible check\n * reports the real problem.\n */\nasync function probeConfigWiring(\n ctx: CheckContext,\n): Promise<ReadonlyArray<ConfigWiringStatus>> {\n try {\n const patchCtx = await loadPatchContext(ctx.cwd, ctx.orca, ctx.cliVersion);\n return await ctx.orca\n .patcherFor(patchCtx.framework.id)\n .verify(patchCtx, { cwd: ctx.cwd });\n } catch {\n return [];\n }\n}\n\n/**\n * Migration path for apps scaffolded before the manifest existed: after a\n * template-mode repair, record the marker-bearing managed files now on disk\n * so the next doctor run gets exact manifest-mode verification instead of\n * template guessing (and its Next-major / template-growth misclassification\n * risk). Marker-less (adopted) files and conditionally-scaffolded ones are\n * deliberately absent.\n *\n * The manifest is only finalized when every current *infrastructure* file is\n * present and recordable (marker-bearing): materializing during an\n * unresolved boundary conflict — or over an adopted boundary — would write a\n * manifest that tracks no request boundary at all, and deleting the boundary\n * later would go undetected. Until then the app stays on the template\n * fallback, whose presence checks keep enforcing the boundary. Best-effort:\n * an unreadable state file leaves the app in template mode, same as before.\n */\nasync function materializeManifest(\n ctx: CheckContext,\n patchCtx: Awaited<ReturnType<typeof loadPatchContext>>,\n): Promise<void> {\n try {\n const actions = ctx.orca.patcherFor(patchCtx.framework.id).artifacts({\n framework: patchCtx.framework,\n rendererId: patchCtx.rendererId,\n });\n const conditional = new Set(actions.conditionalFiles ?? []);\n const marked: string[] = [];\n for (const path of actions.markedFiles) {\n if (conditional.has(path)) {\n continue;\n }\n const contents = await readIfExists(join(ctx.cwd, path));\n if (contents !== undefined && contents.includes(MANAGED_MARKER)) {\n marked.push(path);\n }\n }\n const infrastructure = actions.markedFiles.filter(\n (path) => actions.fileClasses?.[path] === \"infrastructure\" && !conditional.has(path),\n );\n if (!infrastructure.every((path) => marked.includes(path))) {\n return;\n }\n await writeScaffoldManifest({ cwd: ctx.cwd, actions, written: marked });\n } catch {\n // state.json unreadable or the write raced — stays in template mode.\n }\n}\n\nasync function evaluateManifest(\n cwd: string,\n manifest: ScaffoldManifest,\n): Promise<{ mode: \"manifest\"; rows: ScaffoldFileRow[] }> {\n const rows: ScaffoldFileRow[] = [];\n for (const [path, entry] of Object.entries(manifest.files)) {\n const contents = await readIfExists(join(cwd, path));\n rows.push({ path, class: entry.class, state: stateFor(contents, entry.hash) });\n }\n return { mode: \"manifest\", rows };\n}\n\n/**\n * Fallback for apps scaffolded before the manifest existed: derive the\n * expected set from the patcher's current templates. Conditionally-written\n * files (e.g. the framework home page) are excluded — without a manifest\n * there is no way to know whether setup ever wrote them. Presence-only:\n * no recorded hash means `pristine` vs `edited` cannot be told apart.\n */\nasync function evaluateTemplates(\n ctx: CheckContext,\n): Promise<{ mode: \"template\"; rows: ScaffoldFileRow[] } | undefined> {\n const actions = await resolveArtifacts(ctx);\n if (!actions) {\n return undefined;\n }\n const conditional = new Set(actions.conditionalFiles ?? []);\n const rows: ScaffoldFileRow[] = [];\n for (const path of actions.markedFiles) {\n if (conditional.has(path)) {\n continue;\n }\n const contents = await readIfExists(join(ctx.cwd, path));\n rows.push({\n path,\n class: actions.fileClasses?.[path] ?? \"presentation\",\n state: stateFor(contents, undefined),\n });\n }\n return { mode: \"template\", rows };\n}\n\n/**\n * Resolves the patcher artifacts the same way `eject` does, tolerating every\n * failure with `undefined`: a broken framework detection, an unreadable\n * config, or an unresolvable renderer are reported by their own checks —\n * this one only degrades to \"cannot enumerate\".\n */\nasync function resolveArtifacts(ctx: CheckContext): Promise<EjectActions | undefined> {\n const framework = await ctx.orca.tryDetect(ctx.cwd);\n if (!framework) {\n return undefined;\n }\n try {\n const config = await readZitadelConfig(ctx.cwd).catch(() => ({}) as Record<string, unknown>);\n return ctx.orca.patcherFor(framework.id).artifacts({\n framework,\n rendererId: readRendererId(config),\n });\n } catch {\n return undefined;\n }\n}\n\nfunction stateFor(contents: string | undefined, hash: string | undefined): ScaffoldFileState {\n if (contents === undefined) {\n return \"missing\";\n }\n if (!contents.includes(MANAGED_MARKER)) {\n return \"adopted\";\n }\n if (hash === undefined) {\n return \"managed\";\n }\n return hashScaffoldFile(contents) === hash ? \"pristine\" : \"edited\";\n}\n\nasync function missingManifestPaths(cwd: string, manifest: ScaffoldManifest): Promise<string[]> {\n const missing: string[] = [];\n for (const path of Object.keys(manifest.files)) {\n if ((await readIfExists(join(cwd, path))) === undefined) {\n missing.push(path);\n }\n }\n return missing;\n}\n\nasync function readIfExists(path: string): Promise<string | undefined> {\n try {\n return await readFile(path, \"utf8\");\n } catch {\n return undefined;\n }\n}\n\nfunction listPaths(rows: ReadonlyArray<ScaffoldFileRow>): string {\n return rows.map((row) => row.path).join(\", \");\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","import { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { ZitadelError } from \"./errors\";\n\n/**\n * Read every `*.json` file under `absDir` and return each body as a plain\n * object. Files are read in lexical filename order so the result is\n * deterministic for downstream hashing and diffs. Each file is parsed by\n * `JSON.parse`; this function does **not** apply any schema validation —\n * unknown keys, forward-compatible fields, and `${VAR}` placeholders survive\n * intact. Callers that need a typed shape pass the result through their\n * resource's Zod schema.\n *\n * Returns an empty array when the directory is missing. Throws `E_VALIDATION`\n * `ZitadelError` on invalid JSON or when a file's root value is not an object.\n *\n * @param absDir - Absolute path to the directory to scan.\n */\nexport async function readJsonDir(absDir: string): Promise<ReadonlyArray<Record<string, unknown>>> {\n let entries: string[];\n try {\n entries = await readdir(absDir);\n } catch (error) {\n if (typeof error === \"object\" && error !== null && \"code\" in error && error.code === \"ENOENT\") {\n return [];\n }\n throw error;\n }\n const result: Record<string, unknown>[] = [];\n for (const entry of entries.filter((name) => name.endsWith(\".json\")).sort()) {\n const abs = join(absDir, entry);\n let raw: unknown;\n try {\n raw = JSON.parse(await readFile(abs, \"utf8\"));\n } catch {\n throw new ZitadelError(\"E_VALIDATION\", `${entry} is not valid JSON`);\n }\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n throw new ZitadelError(\"E_VALIDATION\", `${entry} must contain a JSON object at the root`);\n }\n result.push(raw as Record<string, unknown>);\n }\n return result;\n}\n","import { join } from \"node:path\";\n\nimport { schemaConfigSchema } from \"@zitadel/config/schemas\";\n\nimport { readJsonDir } from \"../../../lib/json-dir\";\nimport { SCHEMAS_DIR } from \"../../../lib/user-schema\";\nimport { AbstractSanityCheck, type CheckContext, type CheckOutcome } from \"./types\";\n\n/**\n * Verifies local schema config files round-trip through the canonical\n * `schemaConfigSchema` from `@zitadel/config/schemas` — the same Zod the\n * sync engine validates with, so doctor and `apply` can never disagree\n * about a file. The union enforces the `kind` discriminator\n * (`user-schema` / `schema-url`) and the `metaSchema`/`x-auth-methods`/etc.\n * fields the platform requires.\n */\nexport class SchemaCheck extends AbstractSanityCheck {\n readonly name = \"schema\";\n readonly path = SCHEMAS_DIR;\n protected readonly summary = \"User schemas are valid Zitadel schema bodies\";\n\n /**\n * An empty `.zitadel/schemas/` is a warning, not a failure: projects\n * created before editable config existed were seeded server-side and have\n * no local schema files, and there is no safe auto-fix that could invent\n * them. Only invalid files fail the check.\n */\n override async run(ctx: CheckContext): Promise<CheckOutcome> {\n const schemas = await readJsonDir(join(ctx.cwd, SCHEMAS_DIR));\n if (schemas.length === 0) {\n return {\n name: this.name,\n status: \"warn\",\n message:\n `No schema files found in ${SCHEMAS_DIR} — this project predates editable ` +\n \"schema config or setup was interrupted. New projects scaffold editable \" +\n \"defaults via `zitadel setup`.\",\n path: this.path,\n };\n }\n return super.run(ctx);\n }\n\n protected async verify(ctx: CheckContext): Promise<void> {\n const schemas = await readJsonDir(join(ctx.cwd, SCHEMAS_DIR));\n for (const schema of schemas) {\n const result = schemaConfigSchema.safeParse(schema);\n if (!result.success) {\n throw new Error(\n result.error.issues\n .map((issue) => `${issue.path.join(\".\") || \"/\"} ${issue.message}`)\n .join(\"; \"),\n );\n }\n }\n }\n}\n","import { claimState, type ClaimState } from \"../../../lib/claim-state\";\nimport { readProjectServer, readZitadelConfig, readZitadelSecret } from \"../../../lib/project\";\nimport type { CheckContext, CheckOutcome, SanityCheck } from \"./types\";\n\n/**\n * Reports whether the project is attached to a team, reading `claimed_at` and\n * `team_id` from `.zitadel/secret`.\n *\n * Always advisory, never a failure. An unattached project works exactly like an\n * attached one — same issuer, same users, same applications — so the only thing\n * missing is durability, which is the developer's call and not a defect. That\n * matters mechanically too: `doctor` turns any `fail` into a thrown\n * `E_VALIDATION`, so failing here would break every scripted `zitadel doctor`\n * against a project nobody had claimed yet.\n *\n * Implements {@link SanityCheck} directly rather than via the abstract base,\n * for the same reason `ManagedFilesCheck` does: the base's `verify`-throws\n * contract can only express pass/fail, and this check is only ever warn or\n * pass.\n */\nexport class ClaimCheck implements SanityCheck {\n readonly name = \"claim\";\n readonly path = \".zitadel/secret\";\n\n async run(ctx: CheckContext): Promise<CheckOutcome> {\n let state: ClaimState;\n try {\n state = claimState({\n secret: await readZitadelSecret(ctx.cwd),\n // From `zitadel.json`, not the command's own source: `doctor` pins its\n // source to the local runtime URL, so asking it where the project lives\n // would report every project as local.\n server: readProjectServer(await readZitadelConfig(ctx.cwd)),\n });\n } catch {\n // A missing or unparseable secret/config is already reported, loudly and\n // with a repair path, by the `secret` and `config` checks. Implementing\n // `SanityCheck` directly means nothing wraps a throw here, so swallowing\n // it is what keeps a broken project reporting its real problem instead of\n // crashing the whole battery on a nudge.\n return {\n name: this.name,\n status: \"pass\",\n message: \"Skipped: could not read the project files that record the owning team\",\n path: this.path,\n };\n }\n\n if (state.kind === \"detached\") {\n return {\n name: this.name,\n status: \"warn\",\n message:\n \"This project is temporary until you attach it to a team. Run `zitadel claim` \" +\n \"to make it permanent; nothing about the project changes.\",\n path: this.path,\n };\n }\n\n return {\n name: this.name,\n status: \"pass\",\n message:\n state.kind === \"attached\"\n ? `Project is attached to team ${state.team_id}`\n : // Local and self-hosted servers have no team to attach to, so the\n // check passes rather than warning about an impossible action.\n \"Project is not on a server where teams apply\",\n path: this.path,\n };\n }\n\n /**\n * Deliberately a no-op. `doctor --fix` calls `fix` on every non-passing\n * check, but claiming requires a human to sign in through a browser, so there\n * is nothing safe to automate here.\n */\n async fix(_ctx: CheckContext): Promise<void> {\n return;\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 { DependencyVersionCheck } from \"./dependency-version\";\nimport { ManagedFilesCheck } from \"./managed-files\";\nimport { ProjectMatchCheck } from \"./project-match\";\nimport { SchemaCheck } from \"./schema\";\nimport { ClaimCheck } from \"./claim\";\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 { DependencyVersionCheck } from \"./dependency-version\";\nexport { ManagedFilesCheck } from \"./managed-files\";\nexport { ProjectMatchCheck } from \"./project-match\";\nexport { ClaimCheck } from \"./claim\";\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 new SchemaCheck(),\n new DependencyCheck(),\n new DependencyVersionCheck(),\n new ManagedFilesCheck(),\n new ProjectMatchCheck(),\n new ClaimCheck(),\n];\n","import { Flags } from \"@oclif/core\";\nimport consola from \"consola\";\n\nimport { claimAction, claimCommand } from \"../../lib/claim-state\";\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 discoverManagedRuntimeProcesses,\n type ManagedRuntimeProcess,\n} from \"../../lib/local-server/processes\";\nimport {\n DEFAULT_LOCAL_SERVER_PORT,\n assertLocalStateWritable,\n checkLocalServerHealth,\n defaultLocalServerImageForCliVersion,\n localServerUrl,\n readRuntimeMetadata,\n type RuntimeBackend,\n type RuntimeMetadata,\n} from \"../../lib/local-server/runtime\";\nimport { BaseCommand, type JsonEnvelope } from \"../../lib/oclif\";\nimport { createOrca } from \"../../lib/orca\";\nimport { hasZitadelConfig } from \"../../lib/project\";\nimport { listenersForPort } from \"../../lib/prober/ports\";\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 check that did not pass — failed or warned —\n * first attempts its own repair (a no-op for checks with no safe automatic\n * 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: \"Repair missing files and stale managed wiring.\" }),\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 // Repair warn-level drift too (e.g. a deleted presentation page):\n // fixes are restore-missing-only, so running one on a warning is safe.\n if (before[index]?.status === \"pass\") {\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 this.recordTelemetry({\n runtime: runtimeBackend,\n checks_total: checks.length,\n checks_failed: failed.length,\n checks_warn: warnings.length,\n failed_checks: failed.length > 0 ? failed.map((check) => check.name).join(\",\") : undefined,\n });\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 // A check that failed with a typed CLI error advertises its own\n // category (e.g. the framework floor's E_UNSUPPORTED_PROJECT_SHAPE) —\n // surface that instead of the generic validation class so agents can\n // branch on it. The port check keeps its dedicated code first.\n const code = failed.some((check) => check.name === \"port\")\n ? \"E_PORT_IN_USE\"\n : (failed.find((check) => check.code !== undefined)?.code ?? \"E_VALIDATION\");\n throw new ZitadelError(code, \"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 const stopCommand = publicCliCommand(\"stop --all\", cliVersion);\n const retryCommand = publicCliCommand(\"doctor\", cliVersion);\n const alternatePortCommand = publicCliCommand(\n `doctor --port ${String(fallbackPort)}`,\n cliVersion,\n );\n return {\n hint:\n `Port ${String(port)} is already in use. Stop the process using it, ` +\n `run \\`${stopCommand}\\` for CLI-managed local runtimes, then rerun ` +\n `\\`${retryCommand}\\`; or choose another port with \\`${alternatePortCommand}\\`.`,\n nextCommands: [stopCommand, retryCommand, alternatePortCommand],\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 // A failure that surfaced as a typed CLI error carries its own remedy —\n // e.g. the framework floor's upgrade hint. That beats the generic --fix\n // advice below, which cannot repair an unsupported version.\n const typed = failed.find((check) => check.code !== undefined && check.hint !== undefined);\n if (typed?.hint !== undefined) {\n return { hint: typed.hint, nextCommands: [publicCliCommand(\"doctor\", cliVersion)] };\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 const nextActions: string[] = [];\n const nextCommands: string[] = [];\n if (warnings.some((check) => check.name === \"docker-cli\")) {\n const advice = dockerRuntimeGuidance(\"doctor\", cliVersion);\n nextActions.push(...advice.nextActions);\n nextCommands.push(...advice.nextCommands);\n }\n\n if (warnings.some((check) => check.name === \"claim\")) {\n nextActions.push(claimAction(cliVersion));\n nextCommands.push(claimCommand(cliVersion));\n }\n\n const managedRuntimeWarning = warnings.find((check) => check.name === \"managed-runtime-processes\");\n if (hasManagedRuntimeProcesses(managedRuntimeWarning)) {\n nextActions.push(\n \"Review other host-wide CLI-managed local Zitadel runtimes before starting a new one.\",\n );\n nextCommands.push(publicCliCommand(\"stop --all\", cliVersion));\n }\n\n const dependencyRemedy = remedyCommandOf(\n warnings.find((check) => check.name === \"dependency-version\"),\n );\n if (dependencyRemedy !== undefined) {\n nextActions.push(\n \"Align the exactly-pinned @zitadel/* dependencies with the CLI version; scaffolded files and guidance target the CLI's train.\",\n );\n nextCommands.push(dependencyRemedy);\n }\n\n if (nextActions.length === 0 && nextCommands.length === 0) {\n return undefined;\n }\n return { nextActions: unique(nextActions), nextCommands: unique(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 const managedRuntimeCheck = await checkManagedRuntimeProcesses(runtime);\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 () => checkPortAvailability(runtime, port),\n ),\n await checkRuntime(runtime, runtimeBackend),\n managedRuntimeCheck,\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 () => checkPortAvailability(runtime, port),\n ),\n await checkRuntime(runtime, runtimeBackend),\n managedRuntimeCheck,\n ];\n}\n\nasync function checkPortAvailability(\n runtime: RuntimeMetadata | undefined,\n port: number,\n): Promise<string> {\n if (runtime?.port === port && (await checkLocalServerHealth(runtime.server_url))) {\n return `${runtime.server_url} is already healthy`;\n }\n const listeners = await listenersForPort(port);\n if (listeners.length > 0) {\n throw new PortInUseCheckError(port, localServerUrl(port), listeners);\n }\n return `Port ${String(port)} is available`;\n}\n\nclass PortInUseCheckError extends Error {\n constructor(\n readonly port: number,\n readonly serverUrl: string,\n readonly listeners: Awaited<ReturnType<typeof listenersForPort>>,\n ) {\n super(`Port ${String(port)} is already in use by ${formatListeners(listeners)}`);\n }\n}\n\nasync function checkManagedRuntimeProcesses(\n runtime: RuntimeMetadata | undefined,\n): Promise<CheckOutcome> {\n const discovery = await discoverManagedRuntimeProcesses();\n if (!discovery.supported) {\n return {\n name: \"managed-runtime-processes\",\n status: \"warn\",\n message: \"Managed local runtime process discovery is unavailable.\",\n details: { supported: false, error: discovery.error },\n };\n }\n const processes = additionalManagedRuntimeProcesses(discovery.processes, runtime);\n if (processes.length === 0) {\n return {\n name: \"managed-runtime-processes\",\n status: \"pass\",\n message: \"No additional host-wide managed local runtime processes found.\",\n details: { supported: true, scope: \"host\", processes: [] },\n };\n }\n return {\n name: \"managed-runtime-processes\",\n status: \"warn\",\n message: `${String(processes.length)} other host-wide managed local runtime process${processes.length === 1 ? \"\" : \"es\"} found.`,\n details: { supported: true, scope: \"host\", processes },\n };\n}\n\nfunction additionalManagedRuntimeProcesses(\n processes: ReadonlyArray<ManagedRuntimeProcess>,\n runtime: RuntimeMetadata | undefined,\n): ReadonlyArray<ManagedRuntimeProcess> {\n if (runtime?.backend !== \"binary\") {\n return processes;\n }\n return processes.filter((processInfo) => processInfo.pid !== runtime.pid && processInfo.ppid !== runtime.pid);\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 formatListeners(listeners: Awaited<ReturnType<typeof listenersForPort>>): string {\n return listeners\n .map((listener) =>\n [listener.command ?? \"unknown\", listener.pid ? `pid ${String(listener.pid)}` : undefined]\n .filter(Boolean)\n .join(\" \"),\n )\n .join(\", \");\n}\n\n/**\n * A warning may carry its own repair as `details.remedy_command` (today: the\n * dependency-version check's package-manager-aware exact-pin install).\n * Surfacing that string keeps the structured advisory identical to the\n * command quoted in the warning's prose.\n */\nfunction remedyCommandOf(check: CheckOutcome | undefined): string | undefined {\n if (check?.status !== \"warn\") {\n return undefined;\n }\n const details = check.details;\n if (typeof details !== \"object\" || details === null) {\n return undefined;\n }\n const remedy = (details as { remedy_command?: unknown }).remedy_command;\n return typeof remedy === \"string\" && remedy.length > 0 ? remedy : undefined;\n}\n\nfunction hasManagedRuntimeProcesses(check: CheckOutcome | undefined): boolean {\n if (!check || check.status !== \"warn\") {\n return false;\n }\n const details = check.details;\n return (\n typeof details === \"object\" &&\n details !== null &&\n \"supported\" in details &&\n (details as { supported?: unknown }).supported === true &&\n Array.isArray((details as { processes?: unknown }).processes) &&\n ((details as { processes?: unknown[] }).processes?.length ?? 0) > 0\n );\n}\n\nfunction unique(values: string[]): string[] {\n return [...new Set(values)];\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 if (error instanceof PortInUseCheckError) {\n return {\n name,\n status: failureStatus,\n message: error.message,\n details: {\n port: error.port,\n server_url: error.serverUrl,\n listeners: error.listeners,\n },\n };\n }\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 { E as ZitadelError, t as BaseCommand } from "../oclif-CL6-M13m.mjs";
2
- import { a as AGENTS_HEADER, o as removeGuidanceSection, t as createOrca } from "../orca-BWB4zOdw.mjs";
3
- import { c as readZitadelConfig, o as readRendererId } from "../project-yejJSfdJ.mjs";
1
+ import { E as ZitadelError, t as BaseCommand } from "../oclif-CanO3zdt.mjs";
2
+ import { a as AGENTS_HEADER, o as removeGuidanceSection, t as createOrca } from "../orca-Cu0iW1mv.mjs";
3
+ import { c as readZitadelConfig, o as readRendererId } from "../project-CHhot85s.mjs";
4
4
  import { readFile, rename, rm, stat, writeFile } from "node:fs/promises";
5
5
  import { join } from "node:path";
6
6
  //#region src/commands/eject.ts
@@ -128,7 +128,7 @@ var Eject = class Eject extends BaseCommand {
128
128
  removed.push(husk ? rel : `${rel} (managed section)`);
129
129
  }
130
130
  const manualSteps = actions.configEdits.map((rel) => {
131
- if (rel === "package.json" || rel.endsWith("/package.json")) return `Remove the "dev" script setup added to ${rel}`;
131
+ if (rel === "package.json" || rel.endsWith("/package.json")) return `Restore the "dev" script in ${rel} (setup added the script, or pinned its dev-server port)`;
132
132
  if (rel === "angular.json" || rel.endsWith("/angular.json")) return `Remove the Zitadel proxyConfig (and dev-server port) from the serve target in ${rel}`;
133
133
  return `Remove the Zitadel configuration block from ${rel}`;
134
134
  });
@@ -1 +1 @@
1
- {"version":3,"file":"eject.mjs","names":[],"sources":["../../src/commands/eject.ts"],"sourcesContent":["import { readFile, rename, rm, stat, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { BaseCommand, type JsonEnvelope } from \"../lib/oclif\";\nimport { ZitadelError } from \"../lib/errors\";\nimport { createOrca } from \"../lib/orca\";\nimport { AGENTS_HEADER, removeGuidanceSection } from \"../lib/orca/patchers/rule/guidance\";\nimport type { EjectActions } from \"../lib/orca/patchers/types\";\nimport { MANAGED_MARKER } from \"../lib/paths\";\nimport { readRendererId, readZitadelConfig } from \"../lib/project\";\n\n/**\n * Asks the framework patcher which artifacts it owns. Falls back to the\n * framework-agnostic set (`zitadel.json`, `.zitadel/`, `.env.local`) when the\n * framework or its patcher cannot be resolved, so an orphaned/partial project\n * can still be cleaned up.\n */\nasync function resolveEjectActions(cwd: string): Promise<EjectActions> {\n const fallback: EjectActions = {\n markedFiles: [],\n rootConfigFiles: [\"zitadel.json\"],\n directories: [\".zitadel\"],\n envBackups: [\".env.local\"],\n dependencies: [],\n configEdits: [],\n guidanceFiles: [\"AGENTS.md\", \"README.md\"],\n };\n const orca = createOrca();\n const framework = await orca.tryDetect(cwd);\n if (!framework) {\n return fallback;\n }\n try {\n const config = await readZitadelConfig(cwd).catch(() => ({}) as Record<string, unknown>);\n return orca.patcherFor(framework.id).artifacts({\n framework,\n rendererId: readRendererId(config),\n });\n } catch {\n return fallback;\n }\n}\n\n/**\n * Builds the `next_commands` envelope field — manual follow-ups `eject` can't\n * safely run itself: deleting the `.env.local.ejected-*` backups it created\n * (only when some were made), and uninstalling the SDK packages the patcher\n * added (the CLI never modifies the user's `package.json` + lockfile +\n * `node_modules` directly; it just suggests the command).\n */\nfunction assembleNextCommands(\n backedUp: ReadonlyArray<unknown>,\n dependencies: ReadonlyArray<string>,\n): ReadonlyArray<string> {\n const commands: string[] = [];\n if (backedUp.length > 0) {\n commands.push(\"rm -f .env.local.ejected-*\");\n }\n for (const dep of dependencies) {\n commands.push(`npm uninstall ${dep}`);\n }\n return commands;\n}\n\nasync function pathExists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * `zitadel eject` — remove managed files and local Zitadel state.\n *\n * Removes Zitadel-managed files from the project, leaving the remote project\n * untouched. The set of files comes from the framework patcher's\n * {@link import(\"../lib/orca/patchers/types\").Patcher.artifacts}, so the patcher\n * is the single source of truth for what its integration owns.\n *\n * Marked code files are removed only when they still carry the managed marker\n * (user-replaced files are preserved); `zitadel.json` is removed; `.env.local`\n * is renamed to a timestamped backup; and `.zitadel/` is removed wholesale.\n * `--dry-run` reports without touching the filesystem; non-interactive runs\n * require `--force`.\n */\nexport default class Eject extends BaseCommand {\n static override description = \"Remove managed files and local Zitadel state.\";\n static override aliases = [\"uninstall\"];\n\n async run(): Promise<JsonEnvelope> {\n const { flags } = await this.parse(Eject);\n await this.toMeta(flags);\n const { cwd, force, nonInteractive, dryRun } = this.meta;\n\n if (!force && nonInteractive) {\n throw new ZitadelError(\"E_VALIDATION\", \"Eject requires --force in non-interactive mode\", {\n hint: \"Re-run with --force to confirm deletion of managed files.\",\n });\n }\n\n const actions = await resolveEjectActions(cwd);\n const removed: string[] = [];\n const preserved: string[] = [];\n const backedUp: string[] = [];\n\n for (const rel of actions.markedFiles) {\n const abs = join(cwd, rel);\n if (!(await pathExists(abs))) {\n continue;\n }\n const contents = await readFile(abs, \"utf8\").catch(() => \"\");\n if (!contents.includes(MANAGED_MARKER)) {\n preserved.push(rel);\n continue;\n }\n if (!dryRun) {\n await rm(abs, { force: true });\n }\n removed.push(rel);\n }\n\n for (const rel of actions.rootConfigFiles) {\n const abs = join(cwd, rel);\n if (!(await pathExists(abs))) {\n continue;\n }\n if (!dryRun) {\n await rm(abs, { force: true });\n }\n removed.push(rel);\n }\n\n for (const rel of actions.envBackups) {\n const abs = join(cwd, rel);\n if (!(await pathExists(abs))) {\n continue;\n }\n if (dryRun) {\n backedUp.push(`${rel} -> ${rel}.ejected-<timestamp>`);\n continue;\n }\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const backup = `${abs}.ejected-${stamp}`;\n await rename(abs, backup);\n backedUp.push(`${rel} -> ${backup.slice(cwd.length + 1)}`);\n }\n\n for (const rel of actions.directories) {\n const abs = join(cwd, rel);\n if (!(await pathExists(abs))) {\n continue;\n }\n if (!dryRun) {\n await rm(abs, { recursive: true, force: true });\n }\n removed.push(rel);\n }\n\n // Guidance sections live inside user-owned docs (README.md / AGENTS.md):\n // strip only the marker-fenced section so the stale golden path doesn't\n // outlive the files it points at. The whole file goes only when nothing\n // but the scaffold-created header (or whitespace) would remain — i.e. we\n // created it and nobody added anything since.\n for (const rel of actions.guidanceFiles) {\n const abs = join(cwd, rel);\n if (!(await pathExists(abs))) {\n continue;\n }\n const contents = await readFile(abs, \"utf8\").catch(() => \"\");\n const stripped = removeGuidanceSection(contents);\n if (stripped === contents) {\n continue;\n }\n const husk = stripped.trim() === \"\" || stripped.trim() === AGENTS_HEADER.trim();\n if (!dryRun) {\n if (husk) {\n await rm(abs, { force: true });\n } else {\n await writeFile(abs, stripped);\n }\n }\n removed.push(husk ? rel : `${rel} (managed section)`);\n }\n\n // In-place config merges (vite.config.ts / angular.json / nuxt.config.ts)\n // can't be auto-reverted, so surface them as manual cleanup steps. The\n // Angular patcher also edits package.json (a `dev` script, not a config\n // block), so word that one accurately.\n const manualSteps = actions.configEdits.map((rel) => {\n if (rel === \"package.json\" || rel.endsWith(\"/package.json\")) {\n return `Remove the \"dev\" script setup added to ${rel}`;\n }\n if (rel === \"angular.json\" || rel.endsWith(\"/angular.json\")) {\n return `Remove the Zitadel proxyConfig (and dev-server port) from the serve target in ${rel}`;\n }\n return `Remove the Zitadel configuration block from ${rel}`;\n });\n\n if (removed.length === 0 && backedUp.length === 0 && manualSteps.length === 0) {\n return this.emit({ status: \"skipped\", reason: \"nothing-to-eject\", data: { cwd } });\n }\n\n const nextCommands = assembleNextCommands(backedUp, actions.dependencies);\n\n return this.emit({\n status: \"ok\",\n data: {\n title: \"Zitadel ejected. Remote project is untouched.\",\n files_removed: removed,\n files_preserved: preserved,\n backed_up: backedUp,\n next_commands: nextCommands,\n manual_steps: manualSteps,\n },\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;AAiBA,eAAe,oBAAoB,KAAoC;CACrE,MAAM,WAAyB;EAC7B,aAAa,EAAE;EACf,iBAAiB,CAAC,eAAe;EACjC,aAAa,CAAC,WAAW;EACzB,YAAY,CAAC,aAAa;EAC1B,cAAc,EAAE;EAChB,aAAa,EAAE;EACf,eAAe,CAAC,aAAa,YAAY;EAC1C;CACD,MAAM,OAAO,YAAY;CACzB,MAAM,YAAY,MAAM,KAAK,UAAU,IAAI;AAC3C,KAAI,CAAC,UACH,QAAO;AAET,KAAI;EACF,MAAM,SAAS,MAAM,kBAAkB,IAAI,CAAC,aAAa,EAAE,EAA6B;AACxF,SAAO,KAAK,WAAW,UAAU,GAAG,CAAC,UAAU;GAC7C;GACA,YAAY,eAAe,OAAO;GACnC,CAAC;SACI;AACN,SAAO;;;;;;;;;;AAWX,SAAS,qBACP,UACA,cACuB;CACvB,MAAM,WAAqB,EAAE;AAC7B,KAAI,SAAS,SAAS,EACpB,UAAS,KAAK,6BAA6B;AAE7C,MAAK,MAAM,OAAO,aAChB,UAAS,KAAK,iBAAiB,MAAM;AAEvC,QAAO;;AAGT,eAAe,WAAW,MAAgC;AACxD,KAAI;AACF,QAAM,KAAK,KAAK;AAChB,SAAO;SACD;AACN,SAAO;;;;;;;;;;;;;;;;;AAkBX,IAAqB,QAArB,MAAqB,cAAc,YAAY;CAC7C,OAAgB,cAAc;CAC9B,OAAgB,UAAU,CAAC,YAAY;CAEvC,MAAM,MAA6B;EACjC,MAAM,EAAE,UAAU,MAAM,KAAK,MAAM,MAAM;AACzC,QAAM,KAAK,OAAO,MAAM;EACxB,MAAM,EAAE,KAAK,OAAO,gBAAgB,WAAW,KAAK;AAEpD,MAAI,CAAC,SAAS,eACZ,OAAM,IAAI,aAAa,gBAAgB,kDAAkD,EACvF,MAAM,6DACP,CAAC;EAGJ,MAAM,UAAU,MAAM,oBAAoB,IAAI;EAC9C,MAAM,UAAoB,EAAE;EAC5B,MAAM,YAAsB,EAAE;EAC9B,MAAM,WAAqB,EAAE;AAE7B,OAAK,MAAM,OAAO,QAAQ,aAAa;GACrC,MAAM,MAAM,KAAK,KAAK,IAAI;AAC1B,OAAI,CAAE,MAAM,WAAW,IAAI,CACzB;AAGF,OAAI,EAAC,MADkB,SAAS,KAAK,OAAO,CAAC,YAAY,GAAG,EAC9C,SAAA,kCAAwB,EAAE;AACtC,cAAU,KAAK,IAAI;AACnB;;AAEF,OAAI,CAAC,OACH,OAAM,GAAG,KAAK,EAAE,OAAO,MAAM,CAAC;AAEhC,WAAQ,KAAK,IAAI;;AAGnB,OAAK,MAAM,OAAO,QAAQ,iBAAiB;GACzC,MAAM,MAAM,KAAK,KAAK,IAAI;AAC1B,OAAI,CAAE,MAAM,WAAW,IAAI,CACzB;AAEF,OAAI,CAAC,OACH,OAAM,GAAG,KAAK,EAAE,OAAO,MAAM,CAAC;AAEhC,WAAQ,KAAK,IAAI;;AAGnB,OAAK,MAAM,OAAO,QAAQ,YAAY;GACpC,MAAM,MAAM,KAAK,KAAK,IAAI;AAC1B,OAAI,CAAE,MAAM,WAAW,IAAI,CACzB;AAEF,OAAI,QAAQ;AACV,aAAS,KAAK,GAAG,IAAI,MAAM,IAAI,sBAAsB;AACrD;;GAGF,MAAM,SAAS,GAAG,IAAI,4BADR,IAAI,MAAM,EAAC,aAAa,CAAC,QAAQ,SAAS,IAClB;AACtC,SAAM,OAAO,KAAK,OAAO;AACzB,YAAS,KAAK,GAAG,IAAI,MAAM,OAAO,MAAM,IAAI,SAAS,EAAE,GAAG;;AAG5D,OAAK,MAAM,OAAO,QAAQ,aAAa;GACrC,MAAM,MAAM,KAAK,KAAK,IAAI;AAC1B,OAAI,CAAE,MAAM,WAAW,IAAI,CACzB;AAEF,OAAI,CAAC,OACH,OAAM,GAAG,KAAK;IAAE,WAAW;IAAM,OAAO;IAAM,CAAC;AAEjD,WAAQ,KAAK,IAAI;;AAQnB,OAAK,MAAM,OAAO,QAAQ,eAAe;GACvC,MAAM,MAAM,KAAK,KAAK,IAAI;AAC1B,OAAI,CAAE,MAAM,WAAW,IAAI,CACzB;GAEF,MAAM,WAAW,MAAM,SAAS,KAAK,OAAO,CAAC,YAAY,GAAG;GAC5D,MAAM,WAAW,sBAAsB,SAAS;AAChD,OAAI,aAAa,SACf;GAEF,MAAM,OAAO,SAAS,MAAM,KAAK,MAAM,SAAS,MAAM,KAAK,cAAc,MAAM;AAC/E,OAAI,CAAC,OACH,KAAI,KACF,OAAM,GAAG,KAAK,EAAE,OAAO,MAAM,CAAC;OAE9B,OAAM,UAAU,KAAK,SAAS;AAGlC,WAAQ,KAAK,OAAO,MAAM,GAAG,IAAI,oBAAoB;;EAOvD,MAAM,cAAc,QAAQ,YAAY,KAAK,QAAQ;AACnD,OAAI,QAAQ,kBAAkB,IAAI,SAAS,gBAAgB,CACzD,QAAO,0CAA0C;AAEnD,OAAI,QAAQ,kBAAkB,IAAI,SAAS,gBAAgB,CACzD,QAAO,iFAAiF;AAE1F,UAAO,+CAA+C;IACtD;AAEF,MAAI,QAAQ,WAAW,KAAK,SAAS,WAAW,KAAK,YAAY,WAAW,EAC1E,QAAO,KAAK,KAAK;GAAE,QAAQ;GAAW,QAAQ;GAAoB,MAAM,EAAE,KAAK;GAAE,CAAC;EAGpF,MAAM,eAAe,qBAAqB,UAAU,QAAQ,aAAa;AAEzE,SAAO,KAAK,KAAK;GACf,QAAQ;GACR,MAAM;IACJ,OAAO;IACP,eAAe;IACf,iBAAiB;IACjB,WAAW;IACX,eAAe;IACf,cAAc;IACf;GACF,CAAC"}
1
+ {"version":3,"file":"eject.mjs","names":[],"sources":["../../src/commands/eject.ts"],"sourcesContent":["import { readFile, rename, rm, stat, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { BaseCommand, type JsonEnvelope } from \"../lib/oclif\";\nimport { ZitadelError } from \"../lib/errors\";\nimport { createOrca } from \"../lib/orca\";\nimport { AGENTS_HEADER, removeGuidanceSection } from \"../lib/orca/patchers/rule/guidance\";\nimport type { EjectActions } from \"../lib/orca/patchers/types\";\nimport { MANAGED_MARKER } from \"../lib/paths\";\nimport { readRendererId, readZitadelConfig } from \"../lib/project\";\n\n/**\n * Asks the framework patcher which artifacts it owns. Falls back to the\n * framework-agnostic set (`zitadel.json`, `.zitadel/`, `.env.local`) when the\n * framework or its patcher cannot be resolved, so an orphaned/partial project\n * can still be cleaned up.\n */\nasync function resolveEjectActions(cwd: string): Promise<EjectActions> {\n const fallback: EjectActions = {\n markedFiles: [],\n rootConfigFiles: [\"zitadel.json\"],\n directories: [\".zitadel\"],\n envBackups: [\".env.local\"],\n dependencies: [],\n configEdits: [],\n guidanceFiles: [\"AGENTS.md\", \"README.md\"],\n };\n const orca = createOrca();\n const framework = await orca.tryDetect(cwd);\n if (!framework) {\n return fallback;\n }\n try {\n const config = await readZitadelConfig(cwd).catch(() => ({}) as Record<string, unknown>);\n return orca.patcherFor(framework.id).artifacts({\n framework,\n rendererId: readRendererId(config),\n });\n } catch {\n return fallback;\n }\n}\n\n/**\n * Builds the `next_commands` envelope field — manual follow-ups `eject` can't\n * safely run itself: deleting the `.env.local.ejected-*` backups it created\n * (only when some were made), and uninstalling the SDK packages the patcher\n * added (the CLI never modifies the user's `package.json` + lockfile +\n * `node_modules` directly; it just suggests the command).\n */\nfunction assembleNextCommands(\n backedUp: ReadonlyArray<unknown>,\n dependencies: ReadonlyArray<string>,\n): ReadonlyArray<string> {\n const commands: string[] = [];\n if (backedUp.length > 0) {\n commands.push(\"rm -f .env.local.ejected-*\");\n }\n for (const dep of dependencies) {\n commands.push(`npm uninstall ${dep}`);\n }\n return commands;\n}\n\nasync function pathExists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * `zitadel eject` — remove managed files and local Zitadel state.\n *\n * Removes Zitadel-managed files from the project, leaving the remote project\n * untouched. The set of files comes from the framework patcher's\n * {@link import(\"../lib/orca/patchers/types\").Patcher.artifacts}, so the patcher\n * is the single source of truth for what its integration owns.\n *\n * Marked code files are removed only when they still carry the managed marker\n * (user-replaced files are preserved); `zitadel.json` is removed; `.env.local`\n * is renamed to a timestamped backup; and `.zitadel/` is removed wholesale.\n * `--dry-run` reports without touching the filesystem; non-interactive runs\n * require `--force`.\n */\nexport default class Eject extends BaseCommand {\n static override description = \"Remove managed files and local Zitadel state.\";\n static override aliases = [\"uninstall\"];\n\n async run(): Promise<JsonEnvelope> {\n const { flags } = await this.parse(Eject);\n await this.toMeta(flags);\n const { cwd, force, nonInteractive, dryRun } = this.meta;\n\n if (!force && nonInteractive) {\n throw new ZitadelError(\"E_VALIDATION\", \"Eject requires --force in non-interactive mode\", {\n hint: \"Re-run with --force to confirm deletion of managed files.\",\n });\n }\n\n const actions = await resolveEjectActions(cwd);\n const removed: string[] = [];\n const preserved: string[] = [];\n const backedUp: string[] = [];\n\n for (const rel of actions.markedFiles) {\n const abs = join(cwd, rel);\n if (!(await pathExists(abs))) {\n continue;\n }\n const contents = await readFile(abs, \"utf8\").catch(() => \"\");\n if (!contents.includes(MANAGED_MARKER)) {\n preserved.push(rel);\n continue;\n }\n if (!dryRun) {\n await rm(abs, { force: true });\n }\n removed.push(rel);\n }\n\n for (const rel of actions.rootConfigFiles) {\n const abs = join(cwd, rel);\n if (!(await pathExists(abs))) {\n continue;\n }\n if (!dryRun) {\n await rm(abs, { force: true });\n }\n removed.push(rel);\n }\n\n for (const rel of actions.envBackups) {\n const abs = join(cwd, rel);\n if (!(await pathExists(abs))) {\n continue;\n }\n if (dryRun) {\n backedUp.push(`${rel} -> ${rel}.ejected-<timestamp>`);\n continue;\n }\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const backup = `${abs}.ejected-${stamp}`;\n await rename(abs, backup);\n backedUp.push(`${rel} -> ${backup.slice(cwd.length + 1)}`);\n }\n\n for (const rel of actions.directories) {\n const abs = join(cwd, rel);\n if (!(await pathExists(abs))) {\n continue;\n }\n if (!dryRun) {\n await rm(abs, { recursive: true, force: true });\n }\n removed.push(rel);\n }\n\n // Guidance sections live inside user-owned docs (README.md / AGENTS.md):\n // strip only the marker-fenced section so the stale golden path doesn't\n // outlive the files it points at. The whole file goes only when nothing\n // but the scaffold-created header (or whitespace) would remain — i.e. we\n // created it and nobody added anything since.\n for (const rel of actions.guidanceFiles) {\n const abs = join(cwd, rel);\n if (!(await pathExists(abs))) {\n continue;\n }\n const contents = await readFile(abs, \"utf8\").catch(() => \"\");\n const stripped = removeGuidanceSection(contents);\n if (stripped === contents) {\n continue;\n }\n const husk = stripped.trim() === \"\" || stripped.trim() === AGENTS_HEADER.trim();\n if (!dryRun) {\n if (husk) {\n await rm(abs, { force: true });\n } else {\n await writeFile(abs, stripped);\n }\n }\n removed.push(husk ? rel : `${rel} (managed section)`);\n }\n\n // In-place config merges (vite.config.ts / angular.json / nuxt.config.ts)\n // can't be auto-reverted, so surface them as manual cleanup steps.\n // package.json is not a config block: Angular has its `dev` script added\n // outright, while Next and Nuxt keep theirs and only get the dev-server\n // port pinned into it — one line has to cover both, so it names the\n // script and both ways setup touches it rather than claiming the script\n // itself should go.\n const manualSteps = actions.configEdits.map((rel) => {\n if (rel === \"package.json\" || rel.endsWith(\"/package.json\")) {\n return `Restore the \"dev\" script in ${rel} (setup added the script, or pinned its dev-server port)`;\n }\n if (rel === \"angular.json\" || rel.endsWith(\"/angular.json\")) {\n return `Remove the Zitadel proxyConfig (and dev-server port) from the serve target in ${rel}`;\n }\n return `Remove the Zitadel configuration block from ${rel}`;\n });\n\n if (removed.length === 0 && backedUp.length === 0 && manualSteps.length === 0) {\n return this.emit({ status: \"skipped\", reason: \"nothing-to-eject\", data: { cwd } });\n }\n\n const nextCommands = assembleNextCommands(backedUp, actions.dependencies);\n\n return this.emit({\n status: \"ok\",\n data: {\n title: \"Zitadel ejected. Remote project is untouched.\",\n files_removed: removed,\n files_preserved: preserved,\n backed_up: backedUp,\n next_commands: nextCommands,\n manual_steps: manualSteps,\n },\n });\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { E as ZitadelError, h as readRuntimeMetadata, k as publicCliCommand, t as BaseCommand, x as resolveCwd } from "../oclif-CL6-M13m.mjs";
2
- import { a as followContainerLogs, f as binaryLogs, p as followBinaryLogs, t as containerLogs } from "../docker-Ciz9N6uI.mjs";
1
+ import { E as ZitadelError, h as readRuntimeMetadata, j as publicCliCommand, t as BaseCommand, x as resolveCwd } from "../oclif-CanO3zdt.mjs";
2
+ import { a as followContainerLogs, f as binaryLogs, p as followBinaryLogs, t as containerLogs } from "../docker-DcRGTOJa.mjs";
3
3
  import { Flags } from "@oclif/core";
4
4
  //#region src/commands/logs.ts
5
5
  var Logs = class Logs extends BaseCommand {
@@ -1,7 +1,7 @@
1
- import { t as BaseCommand } from "../oclif-CL6-M13m.mjs";
2
- import { l as readZitadelSecret } from "../project-yejJSfdJ.mjs";
3
- import { a as buildSyncPlan, i as summarizePlan, l as makeSyncers, n as enumeratePlanResources, r as renderPlan, t as collectPlanWarnings } from "../sync-Cx2_4rXW.mjs";
4
- import { t as environmentSchema } from "../environment-CuHKxtIO.mjs";
1
+ import { t as BaseCommand } from "../oclif-CanO3zdt.mjs";
2
+ import { l as readZitadelSecret } from "../project-CHhot85s.mjs";
3
+ import { a as buildSyncPlan, i as summarizePlan, l as makeSyncers, n as enumeratePlanResources, r as renderPlan, t as collectPlanWarnings } from "../sync-Bd6vASgg.mjs";
4
+ import { t as environmentSchema } from "../environment-rjRVkJjW.mjs";
5
5
  import { Flags } from "@oclif/core";
6
6
  import { createZitadelClient } from "@zitadel/api/client";
7
7
  import { consola as consola$1 } from "consola";
@@ -1,5 +1,5 @@
1
- import { E as ZitadelError, _ as removeRuntimeMetadata, g as removeLocalData, h as readRuntimeMetadata, k as publicCliCommand, p as localContainerName, t as BaseCommand, x as resolveCwd } from "../oclif-CL6-M13m.mjs";
2
- import { g as stopBinaryRuntime, u as stopAndRemoveContainer } from "../docker-Ciz9N6uI.mjs";
1
+ import { E as ZitadelError, _ as removeRuntimeMetadata, g as removeLocalData, h as readRuntimeMetadata, j as publicCliCommand, p as localContainerName, t as BaseCommand, x as resolveCwd } from "../oclif-CanO3zdt.mjs";
2
+ import { g as stopBinaryRuntime, u as stopAndRemoveContainer } from "../docker-DcRGTOJa.mjs";
3
3
  import { cancel, confirm, isCancel } from "@clack/prompts";
4
4
  //#region src/commands/reset.ts
5
5
  var Reset = class Reset extends BaseCommand {
@@ -1,6 +1,6 @@
1
- import { t as BaseCommand } from "../../oclif-CL6-M13m.mjs";
2
- import { l as readZitadelSecret } from "../../project-yejJSfdJ.mjs";
3
- import { t as environmentSchema } from "../../environment-CuHKxtIO.mjs";
1
+ import { t as BaseCommand } from "../../oclif-CanO3zdt.mjs";
2
+ import { l as readZitadelSecret } from "../../project-CHhot85s.mjs";
3
+ import { t as environmentSchema } from "../../environment-rjRVkJjW.mjs";
4
4
  import { cancel, isCancel, select, spinner } from "@clack/prompts";
5
5
  import { Flags } from "@oclif/core";
6
6
  import { createZitadelClient } from "@zitadel/api/client";
@@ -92,7 +92,7 @@ var SchemasList = class SchemasList extends BaseCommand {
92
92
  }
93
93
  const s = spinner();
94
94
  s.start(`Loading ${String(picked)}…`);
95
- const body = await fetchSchemaRevision(client, String(picked), secret.project_id);
95
+ const body = await fetchSchemaRevision(client, String(picked));
96
96
  s.stop(`Loaded ${String(picked)}`);
97
97
  const pretty = JSON.stringify(body, null, 2);
98
98
  return this.emit({
@@ -117,8 +117,8 @@ var SchemasList = class SchemasList extends BaseCommand {
117
117
  * and an unencoded URL would break the `/schemas/:id` path. Mirrors the
118
118
  * encoding the sync engine's schema syncer applies.
119
119
  */
120
- async function fetchSchemaRevision(client, id, projectId) {
121
- return client.getSchemaById(encodeURIComponent(id), { project_id: projectId });
120
+ async function fetchSchemaRevision(client, id) {
121
+ return client.getSchemaById(encodeURIComponent(id));
122
122
  }
123
123
  function renderTable(objectType, revisions) {
124
124
  const header = `Revisions of objectType "${objectType}" (${revisions.length}, newest first)`;