@zitadel/cli 0.1.0-alpha.17 → 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.
- package/README.md +210 -124
- package/SKILLS.md +159 -17
- package/dist/branding-cygSBPkV.mjs +79 -0
- package/dist/branding-cygSBPkV.mjs.map +1 -0
- package/dist/claim-state-DlfD6Res.mjs +66 -0
- package/dist/claim-state-DlfD6Res.mjs.map +1 -0
- package/dist/commands/apply.mjs +6 -5
- package/dist/commands/apply.mjs.map +1 -1
- package/dist/commands/branding/eject.mjs +104 -0
- package/dist/commands/branding/eject.mjs.map +1 -0
- package/dist/commands/claim.mjs +402 -0
- package/dist/commands/claim.mjs.map +1 -0
- package/dist/commands/doctor.mjs +500 -37
- package/dist/commands/doctor.mjs.map +1 -1
- package/dist/commands/eject.mjs +4 -4
- package/dist/commands/eject.mjs.map +1 -1
- package/dist/commands/logs.mjs +2 -2
- package/dist/commands/plan.mjs +6 -5
- package/dist/commands/plan.mjs.map +1 -1
- package/dist/commands/reset.mjs +2 -2
- package/dist/commands/schemas/list.mjs +11 -11
- package/dist/commands/schemas/list.mjs.map +1 -1
- package/dist/commands/setup.mjs +359 -132
- package/dist/commands/setup.mjs.map +1 -1
- package/dist/commands/start.mjs +3 -3
- package/dist/commands/status.mjs +21 -13
- package/dist/commands/status.mjs.map +1 -1
- package/dist/commands/stop.mjs +3 -3
- package/dist/commands/stop.mjs.map +1 -1
- package/dist/designs-Ckz18Dpo.mjs +38 -0
- package/dist/designs-Ckz18Dpo.mjs.map +1 -0
- package/dist/{docker-pGcTrDIY.mjs → docker-DcRGTOJa.mjs} +4 -3
- package/dist/docker-DcRGTOJa.mjs.map +1 -0
- package/dist/{environment-BQF7LeCz.mjs → environment-rjRVkJjW.mjs} +1 -1
- package/dist/{environment-BQF7LeCz.mjs.map → environment-rjRVkJjW.mjs.map} +1 -1
- package/dist/{journey-guidance-CYVpQszz.mjs → journey-guidance-BGrOX_gT.mjs} +14 -3
- package/dist/{journey-guidance-CYVpQszz.mjs.map → journey-guidance-BGrOX_gT.mjs.map} +1 -1
- package/dist/{oclif-BRdjVNne.mjs → oclif-CanO3zdt.mjs} +247 -43
- package/dist/oclif-CanO3zdt.mjs.map +1 -0
- package/dist/{orca-Dip6DPJ2.mjs → orca-Cu0iW1mv.mjs} +894 -196
- package/dist/orca-Cu0iW1mv.mjs.map +1 -0
- package/dist/package-manager-DFdLcDx1.mjs +194 -0
- package/dist/package-manager-DFdLcDx1.mjs.map +1 -0
- package/dist/{ports-V8JfiNgT.mjs → ports-BM20XIZb.mjs} +2 -2
- package/dist/{ports-V8JfiNgT.mjs.map → ports-BM20XIZb.mjs.map} +1 -1
- package/dist/{processes-BVqYsxT8.mjs → processes-DKHPkU8O.mjs} +1 -1
- package/dist/{processes-BVqYsxT8.mjs.map → processes-DKHPkU8O.mjs.map} +1 -1
- package/dist/{project-BGgv7Bba.mjs → project-CHhot85s.mjs} +57 -4
- package/dist/project-CHhot85s.mjs.map +1 -0
- package/dist/{sync-Cd3z7Q1R.mjs → sync-Bd6vASgg.mjs} +549 -75
- package/dist/sync-Bd6vASgg.mjs.map +1 -0
- package/dist/user-schema-DTuOsdKE.mjs +91 -0
- package/dist/user-schema-DTuOsdKE.mjs.map +1 -0
- package/oclif.manifest.json +227 -5
- package/package.json +9 -6
- package/dist/docker-pGcTrDIY.mjs.map +0 -1
- package/dist/oclif-BRdjVNne.mjs.map +0 -1
- package/dist/orca-Dip6DPJ2.mjs.map +0 -1
- package/dist/project-BGgv7Bba.mjs.map +0 -1
- package/dist/sync-Cd3z7Q1R.mjs.map +0 -1
- package/dist/user-schema-DDz5-lX5.mjs +0 -13
- package/dist/user-schema-DDz5-lX5.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.mjs","names":["stylePath","styleId","styleUrl"],"sources":["../../src/lib/setup-resources.ts","../../src/lib/package-manager.ts","../../src/commands/setup/install.ts","../../src/commands/setup/prompts/cancel.ts","../../src/commands/setup/prompts/dev-port.ts","../../src/commands/setup/prompts/framework-confirm.ts","../../src/commands/setup/prompts/server.ts","../../src/commands/setup/prompts/sign-in-preset.ts","../../src/commands/setup/prompts/pick-framework.ts","../../src/commands/setup/prompts/index.ts","../../src/commands/setup/summary.ts","../../src/commands/setup/index.ts"],"sourcesContent":["import { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport { consola } from \"consola\";\n\nimport type {\n CreateFlowDefinition201,\n CreateSchema201,\n CreateSchemaBody,\n} from \"@zitadel/api/generated/model\";\nimport type { ZitadelClient } from \"@zitadel/api/client\";\nimport {\n DEFAULT_FLOW_CONFIG_PATH,\n DEFAULT_FLOW_SCHEMA_URI,\n DEFAULT_SCHEMA_CONFIG_PATH,\n DEFAULT_SETUP_PRESET,\n flowsReadmeContent,\n getDefaultHumanUserSchema,\n getDefaultLoginFlow,\n schemasReadmeContent,\n type SetupPreset,\n} from \"@zitadel/config/defaults\";\n\nimport { normalizeFlowBody, normalizeSchemaBody } from \"@zitadel/config/normalize\";\n\nimport { FLOWS_DIR } from \"./flows\";\nimport { stableStringify } from \"./json\";\nimport { hashForState, writeBackResource } from \"./sync\";\nimport { updateState } from \"./sync/state\";\nimport { SCHEMAS_DIR } from \"./user-schema\";\nimport { ZitadelError } from \"./errors\";\n\nexport type MaterializeSetupResourcesResult = {\n filesWritten: string[];\n};\n\n/**\n * Scaffolds the versioned local default resources for a new project, uploads\n * them through the schema/flow APIs, and seeds `.zitadel/state.json` with the\n * IDs, hashes, and flow metadata the sync engine expects. Setup calls this only\n * after the framework patcher has created `.zitadel/{flows,schemas}` and the\n * initial state file.\n *\n * The schema is uploaded without an `$id`: the server assigns an opaque id on\n * `POST /schemas`, and the flow file can only be rendered after that id comes\n * back because `flow_definition.user_schema` must reference it.\n */\nexport async function materializeSetupResources(opts: {\n cwd: string;\n client: ZitadelClient;\n projectId: string;\n force: boolean;\n /** Which schema+flow bundle to scaffold; defaults to password-first. */\n preset?: SetupPreset;\n}): Promise<MaterializeSetupResourcesResult> {\n await mkdir(join(opts.cwd, FLOWS_DIR), { recursive: true });\n await mkdir(join(opts.cwd, SCHEMAS_DIR), { recursive: true });\n\n const filesWritten: string[] = [];\n const preset = opts.preset ?? DEFAULT_SETUP_PRESET;\n\n const { $id: _templateId, ...schemaBody } = getDefaultHumanUserSchema({ preset }) as {\n $id?: string;\n } & Record<string, unknown>;\n void _templateId;\n\n const schemaWritten = await writeResourceFile(\n opts.cwd,\n DEFAULT_SCHEMA_CONFIG_PATH,\n schemaBody,\n opts.force,\n );\n if (schemaWritten) {\n filesWritten.push(join(opts.cwd, DEFAULT_SCHEMA_CONFIG_PATH));\n }\n\n const schema = (await opts.client.createSchema(schemaBody as CreateSchemaBody, {\n project_id: opts.projectId,\n })) as CreateSchema201;\n const schemaId = requiredString(schema.id, \"created schema id\");\n // Reconcile the just-written file with the server's stored body so local\n // config matches live state from the first second; a fetch failure keeps\n // the template body and its hash (parity is best-effort at setup).\n let schemaHash = hashForState({ normalize: normalizeSchemaBody }, schemaBody);\n try {\n const canonical = (await opts.client.getSchemaById(encodeURIComponent(schemaId), {\n project_id: opts.projectId,\n })) as object;\n const written = await writeBackResource(\n opts.cwd,\n DEFAULT_SCHEMA_CONFIG_PATH,\n { normalize: normalizeSchemaBody },\n canonical,\n );\n schemaHash = written.hash;\n } catch (err) {\n consola.debug(`fetch created schema ${schemaId} during setup failed:`, err);\n }\n await updateState(opts.cwd, DEFAULT_SCHEMA_CONFIG_PATH, {\n id: schemaId,\n hash: schemaHash,\n });\n\n const flowBody = getDefaultLoginFlow({ userSchemaUrl: schemaId, preset });\n\n const flowWritten = await writeResourceFile(\n opts.cwd,\n DEFAULT_FLOW_CONFIG_PATH,\n flowBody,\n opts.force,\n );\n if (flowWritten) {\n filesWritten.push(join(opts.cwd, DEFAULT_FLOW_CONFIG_PATH));\n }\n\n const flow = (await opts.client.createFlowDefinition({\n project_id: opts.projectId,\n schema_uri: DEFAULT_FLOW_SCHEMA_URI,\n flow_definition: flowBody,\n })) as CreateFlowDefinition201;\n\n let flowHash = hashForState({ normalize: normalizeFlowBody }, flowBody);\n if (flow.flow_definition) {\n const written = await writeBackResource(\n opts.cwd,\n DEFAULT_FLOW_CONFIG_PATH,\n { normalize: normalizeFlowBody, normalizeWrite: normalizeFlowBody },\n flow.flow_definition as object,\n );\n flowHash = written.hash;\n }\n await updateState(opts.cwd, DEFAULT_FLOW_CONFIG_PATH, {\n id: requiredString(flow.id, \"created flow definition id\"),\n hash: flowHash,\n name: flowBody.name,\n status: flowBody.status,\n });\n\n const schemasReadme = join(SCHEMAS_DIR, \"README.md\");\n const flowsReadme = join(FLOWS_DIR, \"README.md\");\n if (await writeReadmeFile(opts.cwd, schemasReadme, schemasReadmeContent())) {\n filesWritten.push(join(opts.cwd, schemasReadme));\n }\n if (await writeReadmeFile(opts.cwd, flowsReadme, flowsReadmeContent())) {\n filesWritten.push(join(opts.cwd, flowsReadme));\n }\n\n return { filesWritten };\n}\n\n/**\n * Write a README file, but never overwrite an existing one. A developer who\n * has edited the README should keep their edits when `setup --force` is\n * re-run.\n */\nasync function writeReadmeFile(\n cwd: string,\n relPath: string,\n content: string,\n): Promise<boolean> {\n const dest = join(cwd, relPath);\n await mkdir(dirname(dest), { recursive: true });\n try {\n await writeFile(dest, content, { flag: \"wx\" });\n return true;\n } catch (error) {\n if (isErrno(error, \"EEXIST\")) {\n return false;\n }\n throw error;\n }\n}\n\nasync function writeResourceFile(\n cwd: string,\n relPath: string,\n body: object,\n force: boolean,\n): Promise<boolean> {\n const contents = `${stableStringify(body)}\\n`;\n try {\n await writeFile(join(cwd, relPath), contents, force ? undefined : { flag: \"wx\" });\n return true;\n } catch (error) {\n if (isErrno(error, \"EEXIST\")) {\n throw new ZitadelError(\"E_CONFLICT\", `${relPath} already exists`, {\n hint: \"Move the file aside or rerun setup with --force if you want setup to replace it.\",\n });\n }\n throw error;\n }\n}\n\nfunction requiredString(value: unknown, label: string): string {\n if (typeof value === \"string\" && value.length > 0) {\n return value;\n }\n throw new ZitadelError(\"E_VALIDATION\", `Missing ${label} in server response.`);\n}\n\nfunction isErrno(error: unknown, code: string): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n (error as NodeJS.ErrnoException).code === code\n );\n}\n","import { spawn } from \"node:child_process\";\nimport { readFile, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport type PackageManager = \"npm\" | \"pnpm\" | \"yarn\" | \"bun\";\n\nexport type PackageCommand = {\n command: PackageManager;\n args: string[];\n display: string;\n};\n\nexport async function detectPackageManager(cwd: string): Promise<PackageManager> {\n const declared = await packageManagerFromManifest(cwd);\n if (declared) {\n return declared;\n }\n if (await exists(join(cwd, \"pnpm-lock.yaml\"))) return \"pnpm\";\n if (await exists(join(cwd, \"yarn.lock\"))) return \"yarn\";\n if (await exists(join(cwd, \"bun.lock\"))) return \"bun\";\n if (await exists(join(cwd, \"bun.lockb\"))) return \"bun\";\n if (await exists(join(cwd, \"package-lock.json\"))) return \"npm\";\n return \"npm\";\n}\n\nexport function installCommandFor(packageManager: PackageManager): PackageCommand {\n return command(packageManager, [\"install\"]);\n}\n\nexport function devCommandFor(packageManager: PackageManager): PackageCommand {\n switch (packageManager) {\n case \"npm\":\n return command(\"npm\", [\"run\", \"dev\"]);\n case \"pnpm\":\n return command(\"pnpm\", [\"dev\"]);\n case \"yarn\":\n return command(\"yarn\", [\"dev\"]);\n case \"bun\":\n return command(\"bun\", [\"run\", \"dev\"]);\n }\n}\n\nexport async function runPackageCommand(\n packageCommand: PackageCommand,\n options: {\n cwd: string;\n env?: NodeJS.ProcessEnv;\n redirectStdoutToStderr?: boolean;\n },\n): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const child = spawn(packageCommand.command, packageCommand.args, {\n cwd: options.cwd,\n env: options.env ?? process.env,\n stdio: options.redirectStdoutToStderr ? [\"ignore\", \"pipe\", \"pipe\"] : \"inherit\",\n });\n\n if (options.redirectStdoutToStderr) {\n child.stdout?.on(\"data\", (chunk) => process.stderr.write(chunk));\n child.stderr?.on(\"data\", (chunk) => process.stderr.write(chunk));\n }\n\n child.on(\"error\", reject);\n child.on(\"close\", (code, signal) => {\n if (code === 0) {\n resolve();\n return;\n }\n const detail = signal ? `signal ${signal}` : `exit ${String(code ?? 1)}`;\n const error = new Error(`${packageCommand.display} failed with ${detail}`);\n Object.assign(error, { code: code ?? 1, signal });\n reject(error);\n });\n });\n}\n\nfunction command(packageManager: PackageManager, args: string[]): PackageCommand {\n return {\n command: packageManager,\n args,\n display: [packageManager, ...args].join(\" \"),\n };\n}\n\nasync function packageManagerFromManifest(cwd: string): Promise<PackageManager | undefined> {\n try {\n const raw = await readFile(join(cwd, \"package.json\"), \"utf8\");\n const parsed = JSON.parse(raw) as { packageManager?: unknown };\n return typeof parsed.packageManager === \"string\"\n ? packageManagerFromString(parsed.packageManager)\n : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction packageManagerFromString(value: string): PackageManager | undefined {\n const name = value.split(\"@\")[0];\n return name === \"npm\" || name === \"pnpm\" || name === \"yarn\" || name === \"bun\" ? name : undefined;\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n","import { consola } from \"consola\";\n\nimport { ZitadelError } from \"../../lib/errors\";\nimport { customizeAndPublishActions, verifyLoginAction } from \"../../lib/journey-guidance\";\nimport {\n detectPackageManager,\n devCommandFor,\n installCommandFor,\n runPackageCommand,\n type PackageCommand,\n type PackageManager,\n} from \"../../lib/package-manager\";\nimport { publicCliCommand } from \"../../lib/public-cli\";\n\ntype InstallReason = \"dry-run\" | \"skip-install\" | \"no-dependency-changes\";\n\nexport type SetupInstall = {\n status: \"completed\" | \"skipped\" | \"not-needed\";\n package_manager: PackageManager;\n command: string;\n reason?: InstallReason;\n};\n\nexport type SetupInstallOutcome = {\n install: SetupInstall;\n devCommand: string;\n /**\n * Journey-staged subset for the human terminal box: the verify mission\n * plus one breadcrumb to `status`/README. Customize/publish guidance stays\n * out until login demonstrably works (Elina, alpha.15).\n */\n boxActions: string[];\n /** Complete journey for the JSON envelope — agents consume all of it. */\n nextActions: string[];\n nextCommands: string[];\n};\n\nexport type SetupInstallInput = {\n cliVersion: string;\n cwd: string;\n depsAdded: ReadonlyArray<string>;\n dryRun: boolean;\n env: NodeJS.ProcessEnv;\n issuer: string;\n json: boolean;\n scaffoldedFramework: boolean;\n skipInstall: boolean;\n run?: typeof runPackageCommand;\n};\n\nexport async function installDependenciesForSetup(\n input: SetupInstallInput,\n): Promise<SetupInstallOutcome> {\n const packageManager = await detectPackageManager(input.cwd);\n const installCommand = installCommandFor(packageManager);\n const devCommand = devCommandFor(packageManager);\n const needsInstall = input.scaffoldedFramework || input.depsAdded.length > 0;\n\n if (!needsInstall) {\n return outcome({\n install: {\n status: \"not-needed\",\n package_manager: packageManager,\n command: installCommand.display,\n reason: \"no-dependency-changes\",\n },\n devCommand: devCommand.display,\n cliVersion: input.cliVersion,\n issuer: input.issuer,\n includeInstallCommand: false,\n });\n }\n\n if (input.dryRun || input.skipInstall) {\n return outcome({\n install: {\n status: \"skipped\",\n package_manager: packageManager,\n command: installCommand.display,\n reason: input.dryRun ? \"dry-run\" : \"skip-install\",\n },\n devCommand: devCommand.display,\n cliVersion: input.cliVersion,\n issuer: input.issuer,\n includeInstallCommand: true,\n });\n }\n\n consola.start(`Installing dependencies with ${installCommand.display}`);\n try {\n await (input.run ?? runPackageCommand)(installCommand, {\n cwd: input.cwd,\n env: input.env,\n redirectStdoutToStderr: input.json,\n });\n } catch (error) {\n throw installFailed(error, installCommand, devCommand, input.cwd);\n }\n consola.success(\"Installed dependencies\");\n\n return outcome({\n install: {\n status: \"completed\",\n package_manager: packageManager,\n command: installCommand.display,\n },\n devCommand: devCommand.display,\n cliVersion: input.cliVersion,\n issuer: input.issuer,\n includeInstallCommand: false,\n });\n}\n\nfunction outcome(input: {\n install: SetupInstall;\n devCommand: string;\n cliVersion: string;\n issuer: string;\n includeInstallCommand: boolean;\n}): SetupInstallOutcome {\n const planCommand = publicCliCommand(\"plan\", input.cliVersion);\n const statusCommand = publicCliCommand(\"status\", input.cliVersion);\n const verifyActions = [\n ...(input.includeInstallCommand ? [`Install dependencies: ${input.install.command}`] : []),\n `Start your project: ${input.devCommand} (then open ${input.issuer}/login)`,\n verifyLoginAction(),\n ];\n const breadcrumb = `Once login works: ${statusCommand} shows your next steps; customizing is covered in your README's Zitadel section.`;\n return {\n install: input.install,\n devCommand: input.devCommand,\n boxActions: [...verifyActions, breadcrumb],\n nextActions: [...verifyActions, ...customizeAndPublishActions(input.cliVersion)],\n nextCommands: input.includeInstallCommand\n ? [input.install.command, input.devCommand, planCommand]\n : [input.devCommand, planCommand],\n };\n}\n\nfunction installFailed(\n error: unknown,\n installCommand: PackageCommand,\n devCommand: PackageCommand,\n cwd: string,\n): ZitadelError {\n return new ZitadelError(\"E_VALIDATION\", `Dependency install failed: ${installCommand.display}`, {\n hint: `Run ${installCommand.display} in ${cwd}, then start the app with ${devCommand.display}.`,\n nextCommands: [installCommand.display],\n details: { command: installCommand.display, cwd, original: errorShape(error) },\n });\n}\n\nfunction errorShape(error: unknown): Record<string, unknown> {\n if (error instanceof Error) {\n return {\n name: error.name,\n message: error.message,\n code: (error as NodeJS.ErrnoException).code,\n };\n }\n return { message: String(error) };\n}\n","import { cancel, isCancel } from \"@clack/prompts\";\n\nimport { ZitadelError } from \"../../../lib/errors\";\n\n/**\n * Converts a clack cancellation (Ctrl-C) into a thrown `E_VALIDATION` rather\n * than a partial answer. Every prompt funnels its clack return value through\n * this so the wizard never proceeds with a sentinel or missing value.\n */\nexport function bail<T>(value: T | symbol): asserts value is T {\n if (isCancel(value)) {\n cancel(\"Setup cancelled.\");\n throw new ZitadelError(\"E_VALIDATION\", \"Setup cancelled by user\");\n }\n}\n","import { text } from \"@clack/prompts\";\n\nimport { bail } from \"./cancel\";\nimport type { PromptContext, SetupAnswers, SetupPrompt } from \"./types\";\n\n/**\n * \"Dev server port\" — defaults to the detected port. The validated answer\n * becomes the issuer URL (`http://localhost:<port>`) via `issuerFromPort`.\n */\nexport class DevPortPrompt implements SetupPrompt {\n async ask(answers: SetupAnswers, ctx: PromptContext): Promise<SetupAnswers> {\n // `--dev-port <n>` is authoritative: skip the prompt so an interactive\n // answer can't override the explicit flag (the base command already folded\n // it into answers.devPort).\n if (ctx.devPortFromFlag) {\n return answers;\n }\n const value = await text({\n message: \"Dev server port\",\n placeholder: String(answers.devPort),\n initialValue: String(answers.devPort),\n validate: (input) => {\n const num = Number.parseInt(input ?? \"\", 10);\n return Number.isFinite(num) && num > 0 && num < 65536\n ? undefined\n : \"Must be a port number\";\n },\n });\n bail(value);\n return { ...answers, devPort: Number.parseInt(String(value), 10) };\n }\n}\n","import { confirm } from \"@clack/prompts\";\n\nimport { ZitadelError } from \"../../../lib/errors\";\nimport { bail } from \"./cancel\";\nimport type { PromptContext, SetupAnswers, SetupPrompt } from \"./types\";\n\n/**\n * \"Detected `<framework>`. Proceed?\" — the wizard's first question. Accepting\n * leaves answers unchanged; declining throws `E_UNSUPPORTED_PROJECT_SHAPE`\n * (the user should re-run with an explicit `--framework`).\n */\nexport class FrameworkConfirmPrompt implements SetupPrompt {\n async ask(answers: SetupAnswers, ctx: PromptContext): Promise<SetupAnswers> {\n const ack = await confirm({\n message: `Detected ${ctx.framework.id}. Proceed?`,\n initialValue: true,\n });\n bail(ack);\n if (ack === false) {\n throw new ZitadelError(\n \"E_UNSUPPORTED_PROJECT_SHAPE\",\n \"Setup cancelled — framework declined\",\n { hint: `Re-run with --framework ${ctx.framework.id} when ready.` },\n );\n }\n return answers;\n }\n}\n","import { select, spinner, text } from \"@clack/prompts\";\n\nimport { detectHealthyLocalServer } from \"../../../lib/local-server/runtime\";\nimport { DEFAULT_SERVER } from \"../../../lib/server\";\nimport { bail } from \"./cancel\";\nimport type { PromptContext, SetupAnswers, SetupPrompt } from \"./types\";\n\n/** Sentinel returned by the choice select when the user picks \"Custom URL\". */\nconst CUSTOM = \"__custom__\";\n\n/**\n * \"Which server should `zitadel.json` point to?\" — Zitadel Cloud, the managed\n * local server we detected, or a custom URL.\n *\n * Before asking, it looks for a healthy local Zitadel server the same way the\n * rest of the CLI does (`detectHealthyLocalServer`: the runtime metadata that\n * `zitadel start` wrote to `.zitadel/local/runtime.json`, falling back to a\n * `/healthz` probe on the default localhost port). A detected server becomes\n * an extra option in the choice list *and* the preselected answer — a user\n * who just ran `zitadel start` almost certainly wants it, and `start`'s own\n * next-step hint says `setup --server local`. Picking it writes the URL\n * directly to `answers.server`; picking \"Custom URL\" still asks for a\n * validated URL exactly as before.\n */\nexport class ServerPrompt implements SetupPrompt {\n async ask(answers: SetupAnswers, ctx: PromptContext): Promise<SetupAnswers> {\n // `--server <url>` overrides the wizard entirely. The base command\n // already validated and resolved the URL into `answers.server`;\n // asking the user to re-pick from a fixed select list when their\n // flag isn't in the list (Cloud / detected / Custom) was a bug —\n // clack would silently default back to Cloud.\n if (ctx.serverFlag) {\n return answers;\n }\n const detected = await detectLocalServer(ctx.cwd);\n\n const choice = await select({\n message: \"Which server should zitadel.json point to?\",\n options: [\n {\n value: DEFAULT_SERVER,\n label: \"Zitadel Cloud (api.zitadel.cloud)\",\n hint: \"recommended for real projects\",\n },\n ...(detected\n ? [\n {\n value: detected,\n label: `Local Zitadel server (${detected})`,\n hint: \"detected — started with zitadel start\",\n },\n ]\n : []),\n { value: CUSTOM, label: \"Custom URL (self-hosted)\" },\n ],\n initialValue: detected ?? answers.server ?? DEFAULT_SERVER,\n });\n bail(choice);\n if (choice !== CUSTOM) {\n return { ...answers, server: choice as string };\n }\n const custom = await text({\n message: \"Server URL\",\n placeholder: \"https://zitadel.internal\",\n validate: (value) => {\n try {\n new URL(value ?? \"\");\n return;\n } catch {\n return \"Must be a valid URL\";\n }\n },\n });\n bail(custom);\n return { ...answers, server: custom as string };\n }\n}\n\n/**\n * Wraps {@link detectHealthyLocalServer} in a spinner: the unhealthy paths\n * block on up to two 1.5s `/healthz` probes, long enough that the wizard\n * should say what it is doing.\n */\nasync function detectLocalServer(cwd: string): Promise<string | undefined> {\n const s = spinner();\n s.start(\"Checking for a local Zitadel server\");\n const detected = await detectHealthyLocalServer(cwd);\n s.stop(\n detected\n ? `Found local Zitadel server at ${detected}.`\n : \"No local Zitadel server detected.\",\n );\n return detected;\n}\n","import { select } from \"@clack/prompts\";\n\nimport { SETUP_PRESETS, type SetupPreset } from \"@zitadel/config/defaults\";\n\nimport { bail } from \"./cancel\";\nimport type { PromptContext, SetupAnswers, SetupPrompt } from \"./types\";\n\n/**\n * \"How should users sign in?\" — picks the schema+flow preset the scaffold\n * starts from (#448: app-type/preset selection before any `.zitadel/` file\n * is written). `--preset` is authoritative; non-interactive runs keep the\n * password-first default seeded by the command.\n */\nexport class SignInPresetPrompt implements SetupPrompt {\n async ask(answers: SetupAnswers, ctx: PromptContext): Promise<SetupAnswers> {\n if (ctx.presetFromFlag) {\n return answers;\n }\n const labels: Record<SetupPreset, string> = {\n \"password-first\": \"Password first — email + password, passkey optional during registration\",\n \"passkey-first\": \"Passkey first — one-tap passkey up front, email + password fallback\",\n };\n const value = await select({\n message: \"How should users sign in?\",\n initialValue: answers.preset,\n options: SETUP_PRESETS.map((preset) => ({ value: preset, label: labels[preset] })),\n });\n bail(value);\n return { ...answers, preset: value as SetupPreset };\n }\n}\n","import { intro, select } from \"@clack/prompts\";\n\nimport { bail } from \"./cancel\";\n\n/**\n * \"Choose a framework to scaffold\" — the only prompt outside the main wizard.\n * Runs at the empty-directory branch (before any other detection), so it owns\n * its own `intro` heading. Returns the chosen framework id; choices come from\n * `Orca.availableFrameworks`.\n */\nexport class PickFrameworkPrompt {\n async ask(\n choices: ReadonlyArray<{ id: string; displayName: string }>,\n ): Promise<string> {\n intro(\"Zitadel setup — new project\");\n const picked = await select({\n message: \"Choose a framework to scaffold\",\n options: choices.map((choice) => ({ value: choice.id, label: choice.displayName })),\n });\n bail(picked);\n return picked as string;\n }\n}\n","/**\n * Public surface for the setup wizard prompts. The `setup` command imports\n * {@link SETUP_PROMPTS} and iterates every entry, threading the answers\n * through each prompt's `ask` so they decide whether to actually ask the\n * user. Add a new question by writing a class and appending an instance to\n * the registry below.\n *\n * {@link PickFrameworkPrompt} is intentionally **not** in {@link SETUP_PROMPTS}\n * — it runs at the empty-directory scaffold branch, before the main wizard\n * starts.\n */\nimport { DevPortPrompt } from \"./dev-port\";\nimport { FrameworkConfirmPrompt } from \"./framework-confirm\";\nimport { ServerPrompt } from \"./server\";\nimport { SignInPresetPrompt } from \"./sign-in-preset\";\nimport type { SetupPrompt } from \"./types\";\n\nexport type { PromptContext, SetupAnswers, SetupPrompt } from \"./types\";\nexport { bail } from \"./cancel\";\nexport { DevPortPrompt } from \"./dev-port\";\nexport { FrameworkConfirmPrompt } from \"./framework-confirm\";\nexport { ServerPrompt } from \"./server\";\nexport { SignInPresetPrompt } from \"./sign-in-preset\";\nexport { PickFrameworkPrompt } from \"./pick-framework\";\n\n/** Every question the main setup wizard asks, in ask order. */\nexport const SETUP_PROMPTS: ReadonlyArray<SetupPrompt> = [\n new FrameworkConfirmPrompt(),\n new ServerPrompt(),\n new DevPortPrompt(),\n new SignInPresetPrompt(),\n];\n","import { readFile, stat } from \"node:fs/promises\";\nimport { basename, join } from \"node:path\";\n\nimport pc from \"picocolors\";\n\nimport { detectPackageManager, type PackageManager } from \"../../lib/package-manager\";\n\n/**\n * Structured end-of-command summary, modelled on the report layout the\n * setup mock specifies: one line per fact, grouped under uppercase section\n * headers, with consistent `✓ label value` formatting. Each {@link Row}\n * carries the label, the primary value (already styled by the caller),\n * and an optional `secondary` shown after a dim `→` to mirror the\n * \"package → file\" lines in the mock.\n */\nexport type Row = {\n label: string;\n value: string;\n secondary?: string;\n};\n\nexport type Section = {\n title: string;\n rows: Row[];\n};\n\n/**\n * Renders the section list as a single multi-line string. Labels are\n * padded to a common width per section so the `✓ label value` columns\n * line up, the title prints in dim gray, and `✓` is green. Values come\n * in pre-styled — use the helpers below ({@link path}, {@link url},\n * {@link id}, {@link dim}) to keep the colour palette consistent with\n * the mock.\n */\nexport function renderSummary(sections: Section[]): string {\n const lines: string[] = [];\n for (const section of sections) {\n if (section.rows.length === 0) continue;\n if (lines.length > 0) lines.push(\"\");\n lines.push(pc.dim(section.title.toUpperCase()));\n const labelWidth = Math.max(...section.rows.map((r) => r.label.length)) + 3;\n for (const row of section.rows) {\n const labelCol = row.label.padEnd(labelWidth);\n const secondary = row.secondary ? ` ${pc.dim(\"→\")} ${row.secondary}` : \"\";\n lines.push(`${pc.green(\"✓\")} ${labelCol}${row.value}${secondary}`);\n }\n }\n return lines.join(\"\\n\");\n}\n\n/** Cyan, for filesystem paths the user can open. */\nexport const path = (s: string): string => pc.cyan(s);\n/** Cyan, for URLs (browser-clickable in most terminals). */\nexport const url = (s: string): string => pc.cyan(s);\n/** Yellow, for opaque ids the user shouldn't try to read. */\nexport const id = (s: string): string => pc.yellow(s);\n/** Dim, for separators and secondary detail. */\nexport const dim = (s: string): string => pc.dim(s);\n\n/**\n * Detected facts about the user's project, surfaced in the `DETECTED`\n * section. {@link detectProjectFacts} reads the on-disk markers (lock\n * file, tsconfig, framework dep version) without any platform call.\n */\nexport type ProjectFacts = {\n framework: string;\n frameworkVersion?: string;\n typescript: boolean;\n packageManager: PackageManager;\n};\n\n/**\n * Reads the project root to identify the framework version, TS presence,\n * and which package manager the user runs. Returns safe defaults (npm\n * fallback, no version) on any error so summary rendering can always proceed.\n */\nexport async function detectProjectFacts(cwd: string, frameworkId: string): Promise<ProjectFacts> {\n const facts: ProjectFacts = {\n framework: frameworkId,\n typescript: await fileExists(join(cwd, \"tsconfig.json\")),\n packageManager: await detectPackageManager(cwd),\n };\n try {\n const raw = await readFile(join(cwd, \"package.json\"), \"utf8\");\n const pj = JSON.parse(raw) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const depPkg = depFromFramework(frameworkId);\n const range = pj.dependencies?.[depPkg] ?? pj.devDependencies?.[depPkg];\n if (range) {\n facts.frameworkVersion = stripRange(range);\n }\n } catch {\n // Missing or unreadable package.json — version stays undefined; the\n // renderer skips that segment, which is the same as the user not\n // having declared the framework dep yet.\n }\n return facts;\n}\n\n/** Formats the project facts as the \"Next.js 15 · TypeScript · npm\" string the mock shows. */\nexport function formatFrameworkLine(facts: ProjectFacts): string {\n const segments: string[] = [];\n const pretty = prettyFramework(facts.framework);\n segments.push(facts.frameworkVersion ? `${pretty} ${facts.frameworkVersion}` : pretty);\n if (facts.typescript) segments.push(\"TypeScript\");\n segments.push(facts.packageManager);\n return segments.join(` ${pc.dim(\"·\")} `);\n}\n\nasync function fileExists(p: string): Promise<boolean> {\n try {\n await stat(p);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction depFromFramework(framework: string): string {\n switch (framework) {\n case \"next\":\n return \"next\";\n case \"nuxt\":\n return \"nuxt\";\n default:\n return framework;\n }\n}\n\nfunction prettyFramework(framework: string): string {\n switch (framework) {\n case \"next\":\n return \"Next.js\";\n case \"nuxt\":\n return \"Nuxt\";\n default:\n return framework;\n }\n}\n\n/** Strips `^`/`~`/`>=`/`v` prefixes from an npm range so the version reads cleanly in the summary. */\nfunction stripRange(range: string): string {\n const trimmed = range.replace(/^([\\^~]|>=?|v)/, \"\").trim();\n // Take the first dotted segment so multi-range strings (`^15.0.0 || ^14.0.0`)\n // collapse to a single readable version in the report.\n const first = trimmed.split(/\\s+/)[0];\n return first ?? trimmed;\n}\n\n/** Returns just the file name from a relative path, for the `→ filename` secondary detail in PACKAGE rows. */\nexport function fileNameOf(p: string): string {\n return basename(p);\n}\n","import { rm } from \"node:fs/promises\";\nimport { basename, join } from \"node:path\";\n\nimport { intro, outro } from \"@clack/prompts\";\nimport { Flags } from \"@oclif/core\";\nimport { createZitadelClient } from \"@zitadel/api/client\";\nimport type { CreateProject201 } from \"@zitadel/api/generated/model\";\nimport {\n DEFAULT_SETUP_PRESET,\n SETUP_PRESETS,\n type SetupPreset,\n} from \"@zitadel/config/defaults\";\nimport { consola } from \"consola\";\n\nimport { toZitadelError, ZitadelError } from \"../../lib/errors\";\nimport { BaseCommand, type JsonEnvelope } from \"../../lib/oclif\";\nimport {\n createOrca,\n inspectScaffoldTarget,\n issuerFromPort,\n type FrameworkFacts,\n type Orca,\n type ScaffoldTarget,\n} from \"../../lib/orca\";\nimport { RENDERER_IDS } from \"../../lib/orca/patchers/rule/next/renderers/registry\";\nimport type { PatchContext } from \"../../lib/orca/patchers/types\";\nimport { hasZitadelConfig, hasZitadelSecret } from \"../../lib/project\";\nimport { publicCliCommand } from \"../../lib/public-cli\";\nimport {\n materializeSetupResources,\n type MaterializeSetupResourcesResult,\n} from \"../../lib/setup-resources\";\nimport { installDependenciesForSetup } from \"./install\";\nimport { PickFrameworkPrompt, SETUP_PROMPTS, type SetupAnswers } from \"./prompts\";\nimport {\n detectProjectFacts,\n fileNameOf,\n formatFrameworkLine,\n id as styleId,\n path as stylePath,\n renderSummary,\n url as styleUrl,\n type Row,\n type Section,\n} from \"./summary\";\n\n/**\n * The frameworks `--framework` accepts, derived from Orca's registry so the\n * flag can't drift from what the CLI can actually scaffold. `createOrca` is\n * pure (it only builds the in-memory registries), so this is safe at module\n * load.\n */\nconst FRAMEWORK_OPTIONS = createOrca()\n .availableFrameworks()\n .map((framework) => framework.id);\n\n/** `zitadel setup` — create a project and scaffold local auth.\n *\n * Detects (or, for an empty directory, scaffolds then re-detects) the\n * framework, runs the wizard prompts to fill in any answers not pre-supplied\n * by flags, creates the remote project without server fallback defaults,\n * patches the local files via `Orca`'s framework patcher, then scaffolds and\n * uploads editable schema/flow config from `.zitadel/**`.\n *\n * Every interactive question lives in {@link SETUP_PROMPTS} (the main wizard\n * — each entry is a small class) and {@link PickFrameworkPrompt} (the\n * empty-directory framework choice, before the main wizard).\n */\nexport default class Setup extends BaseCommand {\n static override description = \"Create a Zitadel project and scaffold local auth.\";\n static override examples = [\n \"<%= config.bin %> setup --framework next\",\n \"<%= config.bin %> setup --framework react --dev-port 3000\",\n ];\n static override flags = {\n framework: Flags.string({ description: \"Framework to target.\", options: FRAMEWORK_OPTIONS }),\n renderer: Flags.string({\n description: \"Renderer (default: react).\",\n options: [...RENDERER_IDS],\n }),\n \"dev-port\": Flags.integer({\n description:\n \"Dev-server port; also the issuer origin registered with Zitadel. Defaults to the detected port. Use distinct ports to run several scaffolded apps side by side.\",\n }),\n \"skip-install\": Flags.boolean({\n description: \"Do not install dependencies after setup updates package.json.\",\n }),\n preset: Flags.string({\n description:\n \"Sign-in preset for the scaffolded schema and login flow (default: password-first).\",\n options: [...SETUP_PRESETS],\n }),\n };\n\n async run(): Promise<JsonEnvelope> {\n const { flags } = await this.parse(Setup);\n try {\n await this.toMeta(flags);\n } catch (error) {\n throw localSetupHint(error, retryOptionsFromFlags(flags), this.config.version);\n }\n const { cwd, nonInteractive, dryRun, force } = this.meta;\n\n if (await hasZitadelConfig(cwd)) {\n return this.emit({ status: \"skipped\", reason: \"already-initialized\" });\n }\n if (await hasZitadelSecret(cwd)) {\n throw new ZitadelError(\"E_CONFLICT\", \".zitadel/secret exists without zitadel.json\", {\n hint: \"Move the secret aside or restore zitadel.json before running setup.\",\n });\n }\n\n const orca = createOrca();\n\n consola.start(`Detecting framework in ${shortPath(cwd)}`);\n let framework: FrameworkFacts;\n let scaffoldedFramework = false;\n try {\n framework = await orca.detect(cwd, flags.framework);\n consola.success(\n `Detected ${framework.id}${framework.devPort ? ` (dev port ${framework.devPort})` : \"\"}`,\n );\n } catch (error) {\n if (\n error instanceof ZitadelError &&\n error.code === \"E_FRAMEWORK_NOT_DETECTED\"\n ) {\n const target = await inspectScaffoldTarget(cwd);\n if (!target.scaffoldable) {\n throw frameworkDetectionWithScaffoldTarget(error, cwd, target);\n }\n consola.info(\"Fresh app directory — scaffolding a fresh project\");\n framework = await orca.scaffold(\n cwd,\n await resolveScaffoldFramework(flags.framework, nonInteractive, orca),\n );\n scaffoldedFramework = true;\n consola.success(`Scaffolded ${framework.id} skeleton`);\n } else {\n throw error;\n }\n }\n\n this.recordTelemetry({\n framework: framework.id,\n renderer: flags.renderer ?? \"react\",\n scaffolded_skeleton: scaffoldedFramework,\n skip_install: Boolean(flags[\"skip-install\"]),\n dev_port_explicit: flags[\"dev-port\"] !== undefined,\n preset: flags.preset ?? DEFAULT_SETUP_PRESET,\n step: \"framework_resolved\",\n });\n\n // An explicit --dev-port overrides the detected port for the whole run, so\n // the issuer and the registered origin track the requested port (and several\n // apps can be scaffolded on distinct ports). The config edits set the\n // dev-server port only when it is unset, so a project that already pins a\n // different port in vite.config.*/angular.json keeps it — pass --dev-port to\n // match that pin (or remove it) if the origin check rejects requests.\n if (flags[\"dev-port\"] !== undefined) {\n const devPort = flags[\"dev-port\"];\n if (!Number.isInteger(devPort) || devPort < 1 || devPort > 65535) {\n throw new ZitadelError(\n \"E_VALIDATION\",\n `--dev-port must be an integer in 1..65535, got ${devPort}`,\n );\n }\n framework = {\n ...framework,\n devPort,\n url: issuerFromPort(devPort),\n };\n }\n\n let answers: SetupAnswers = {\n server: this.meta.source,\n devPort: framework.devPort,\n preset: (flags.preset as SetupPreset | undefined) ?? DEFAULT_SETUP_PRESET,\n };\n\n if (!nonInteractive && !dryRun) {\n intro(\"Zitadel setup\");\n const promptCtx = {\n framework,\n cwd,\n serverFlag: this.meta.serverFlag,\n devPortFromFlag: flags[\"dev-port\"] !== undefined,\n presetFromFlag: flags.preset !== undefined,\n };\n for (const prompt of SETUP_PROMPTS) {\n answers = await prompt.ask(answers, promptCtx);\n }\n outro(\"Configuration captured\");\n }\n\n // The interactive prompt can override the flag/default preset recorded at\n // framework_resolved — re-record so telemetry carries the preset that\n // actually scaffolds.\n this.recordTelemetry({ preset: answers.preset });\n\n const issuer = issuerFromPort(answers.devPort);\n // The DevPortPrompt can change the port interactively, so fold the answer\n // back into the framework: the patched dev-server config reads\n // `framework.devPort`, and it must agree with the issuer and the registered\n // origin (both derived from `answers.devPort`).\n framework = { ...framework, devPort: answers.devPort, url: issuer };\n\n // `POST /projects` is unauthenticated. CLI-managed projects opt out of\n // server fallback defaults, then setup uploads the local default schema and\n // flow files through the typed resource APIs and records the returned IDs.\n consola.start(`Creating project on ${answers.server}${dryRun ? \" (dry run)\" : \"\"}`);\n const unauthClient = createZitadelClient({ baseUrl: answers.server });\n const projectName = defaultProjectName(cwd, framework.id);\n // Register the app's own origin so the backend's origin check allows\n // requests the dev proxy forwards from it.\n const project = dryRun\n ? dryRunProject(issuer)\n : await createProjectWithLocalHint(\n unauthClient,\n answers.server,\n this.meta.cliVersion,\n projectName,\n issuer,\n {\n // Resolved values, not raw flags: the wizard may have picked the\n // preset or dev port interactively, and the retry must reproduce\n // those choices — the issuer registered with the project derives\n // from the port.\n ...retryOptionsFromFlags(flags),\n framework: framework.id,\n preset: answers.preset,\n devPort: answers.devPort,\n },\n );\n consola.success(`Created project ${project.id}`);\n this.recordTelemetry({ step: \"project_created\" });\n\n const ctx: PatchContext = {\n framework,\n rendererId: flags.renderer ?? \"react\",\n project,\n issuer,\n server: answers.server,\n cliVersion: this.meta.cliVersion,\n scaffoldedFramework,\n preset: answers.preset,\n };\n consola.start(`Patching project files${dryRun ? \" (dry run)\" : \"\"}`);\n const result = await orca.patcherFor(framework.id).patch(ctx, { cwd, dryRun, force });\n for (const file of result.filesWritten) {\n const sentence = describeWrittenFile(relativeDisplay(cwd, file), dryRun);\n if (sentence) consola.info(sentence);\n }\n for (const file of result.filesSkipped) {\n consola.info(`Left ${relativeDisplay(cwd, file)} unchanged (already matches target)`);\n }\n let resourceResult: MaterializeSetupResourcesResult;\n try {\n resourceResult = dryRun\n ? { filesWritten: [] }\n : await materializeSetupResources({\n cwd,\n client: createZitadelClient({ baseUrl: answers.server, token: project.projectSecret }),\n projectId: project.id,\n force,\n preset: answers.preset,\n });\n } catch (error) {\n // Setup is not atomic: the patcher already wrote `zitadel.json` (the\n // marker the already-initialized guard skips on) and `.zitadel/secret`.\n // Remove both so a rerun starts a fresh setup instead of being skipped\n // forever with no default schema or login flow anywhere. The\n // half-provisioned project has no usable resources, so its credentials\n // are not worth keeping.\n await rm(join(cwd, \"zitadel.json\"), { force: true });\n await rm(join(cwd, \".zitadel/secret\"), { force: true });\n const cause = toZitadelError(error);\n throw new ZitadelError(cause.code, `Default resource setup failed: ${cause.message}`, {\n hint:\n \"The project was created but its default schema/flow upload did not finish. \" +\n \"Re-run `zitadel setup` to start over (add --force to overwrite partially \" +\n \"written .zitadel files).\",\n nextCommands: [\"zitadel setup --force\"],\n details: cause.details,\n });\n }\n for (const file of resourceResult.filesWritten) {\n const sentence = describeWrittenFile(relativeDisplay(cwd, file), dryRun);\n if (sentence) consola.info(sentence);\n }\n const allFilesWritten = [...result.filesWritten, ...resourceResult.filesWritten];\n consola.success(\n `Patched ${allFilesWritten.length} file${allFilesWritten.length === 1 ? \"\" : \"s\"}` +\n (result.filesSkipped.length > 0 ? ` (${result.filesSkipped.length} unchanged)` : \"\"),\n );\n this.recordTelemetry({\n step: \"files_patched\",\n files_written_count: allFilesWritten.length,\n });\n\n const installOutcome = await installDependenciesForSetup({\n cliVersion: this.meta.cliVersion,\n cwd,\n depsAdded: result.depsAdded,\n dryRun,\n env: this.meta.env,\n issuer,\n json: this.jsonEnabled(),\n scaffoldedFramework,\n skipInstall: Boolean(flags[\"skip-install\"]),\n });\n\n this.recordTelemetry({\n step: \"dependencies_installed\",\n package_manager: installOutcome.install.package_manager,\n });\n\n const writtenRel = allFilesWritten.map((file) => relativeDisplay(cwd, file));\n // The structured report is human-only. Under `--json` we let the\n // envelope returned from `this.emit(...)` be the sole stdout\n // payload (oclif requires single-doc JSON).\n if (!this.jsonEnabled()) {\n const projectFacts = await detectProjectFacts(cwd, framework.id);\n const sections = buildSummary({\n projectFacts,\n writtenRel,\n project,\n server: answers.server,\n issuer,\n scaffoldedFramework,\n });\n // Frame the report in a consola box so it reads as a distinct\n // status panel separate from the per-step narration above it.\n // `box` accepts ANSI-styled text in the message body, so our\n // pre-coloured rows (path/url/id helpers) survive intact.\n consola.box({\n title: \"Zitadel is ready\",\n message: [renderSummary(sections), \"\", installOutcome.boxActions.join(\"\\n\")].join(\"\\n\"),\n style: { padding: 1, borderStyle: \"rounded\", borderColor: \"green\" },\n });\n }\n\n return this.emit({\n status: \"ok\",\n // Human-facing output was already shown via consola (box + per-step\n // narration). Pass an empty `pretty` so the base command's fallback\n // renderer doesn't duplicate the summary on stdout. The JSON envelope\n // still carries the full structured payload.\n pretty: \"\",\n data: {\n title: \"Zitadel is ready.\",\n project: { project_id: project.id, issuer },\n framework: framework.id,\n server: answers.server,\n files_written: allFilesWritten.map((file) => relativeDisplay(cwd, file)),\n files_skipped: result.filesSkipped.map((file) => relativeDisplay(cwd, file)),\n install: installOutcome.install,\n next_actions: installOutcome.nextActions,\n next_commands: installOutcome.nextCommands,\n },\n });\n }\n}\n\nfunction frameworkDetectionWithScaffoldTarget(\n error: ZitadelError,\n cwd: string,\n target: ScaffoldTarget,\n): ZitadelError {\n return new ZitadelError(\n error.code,\n \"Could not detect a supported app framework, and this directory is not a fresh scaffold target\",\n {\n hint:\n `${target.reason ?? \"Directory is not empty.\"} ` +\n \"Run setup from an empty directory to scaffold a new app, or run setup from an existing supported app project.\",\n details: { cwd, entries: target.entries, reason: target.reason },\n },\n );\n}\n\n/**\n * Resolves which framework to scaffold into an empty directory: the explicit\n * `--framework`, else PickFrameworkPrompt, else a hard error in non-interactive\n * mode (an agent must pass `--framework`).\n */\nasync function resolveScaffoldFramework(\n framework: string | undefined,\n nonInteractive: boolean,\n orca: Orca,\n): Promise<string> {\n if (framework) {\n return framework;\n }\n if (nonInteractive) {\n throw new ZitadelError(\"E_FRAMEWORK_NOT_DETECTED\", \"Empty directory — pass --framework\", {\n hint: \"Run without --json/--non-interactive to choose from a prompt, or pass --framework for scripted setup.\",\n });\n }\n return new PickFrameworkPrompt().ask(orca.availableFrameworks());\n}\n\n/** A deterministic stand-in project for `--dry-run`, so no remote call is made. */\nfunction dryRunProject(issuer: string): CreateProject201 {\n return {\n id: \"dry-run-0000\",\n projectSecret: \"sk_proj_dry_run_full\",\n previewSecret: \"sk_proj_dry_run_preview\",\n previewOrigins: [issuer],\n createdAt: \"2026-04-21T14:03:11.000Z\",\n };\n}\n\n/**\n * The parts of a setup invocation that a retry suggestion must reproduce.\n * Suggested retries are followed verbatim (especially by agents), so dropping\n * a flag here silently changes what the retry scaffolds.\n */\ntype SetupRetryOptions = {\n framework?: string;\n preset?: SetupPreset;\n renderer?: string;\n devPort?: number;\n nonInteractive?: boolean;\n};\n\n/**\n * Reconstructs the flag list of the current invocation for retry guidance,\n * ending in `--server local`. Flags whose resolved value equals the default\n * are omitted — the retry reproduces the same outcome without them.\n */\nfunction setupRetryFlags(opts: SetupRetryOptions): string {\n const parts: string[] = [];\n if (opts.framework) {\n parts.push(`--framework ${opts.framework}`);\n }\n if (opts.preset && opts.preset !== DEFAULT_SETUP_PRESET) {\n parts.push(`--preset ${opts.preset}`);\n }\n if (opts.renderer && opts.renderer !== \"react\") {\n parts.push(`--renderer ${opts.renderer}`);\n }\n if (opts.devPort !== undefined) {\n parts.push(`--dev-port ${opts.devPort}`);\n }\n if (opts.nonInteractive) {\n parts.push(\"--non-interactive\");\n }\n parts.push(\"--server local\");\n return parts.join(\" \");\n}\n\n/**\n * Retry options straight from parsed flags, for failures before the wizard\n * resolves answers. `--non-interactive` is echoed only when explicitly passed\n * — TTY/JSON-inferred non-interactivity re-infers itself on the retry.\n */\nfunction retryOptionsFromFlags(flags: {\n framework?: string;\n preset?: string;\n renderer?: string;\n \"dev-port\"?: number;\n \"non-interactive\"?: boolean;\n}): SetupRetryOptions {\n return {\n framework: flags.framework,\n preset: flags.preset as SetupPreset | undefined,\n renderer: flags.renderer,\n devPort: flags[\"dev-port\"],\n nonInteractive: Boolean(flags[\"non-interactive\"]),\n };\n}\n\nasync function createProjectWithLocalHint(\n client: ReturnType<typeof createZitadelClient>,\n server: string,\n cliVersion: string,\n projectName: string,\n issuer: string,\n retry: SetupRetryOptions,\n): Promise<CreateProject201> {\n try {\n // API contract requires a project name; generated TS models may lag\n // briefly until `packages/api` regeneration catches up.\n const payload = { name: projectName, previewOrigins: [issuer], seedDefaults: false } as {\n name: string;\n previewOrigins: string[];\n seedDefaults: false;\n };\n // Register the app's own origin so the backend's origin check allows the\n // requests the dev proxy forwards from it.\n return await client.createProject(payload as Parameters<typeof client.createProject>[0]);\n } catch (error) {\n const normalized = toZitadelError(error);\n const retryFlags = setupRetryFlags(retry);\n throw new ZitadelError(normalized.code, normalized.message, {\n hint:\n `${normalized.hint ? `${normalized.hint} ` : \"\"}` +\n \"If you meant to use a local Zitadel server, start it first \" +\n `and retry setup with ${retryFlags}.`,\n nextCommands: [\n publicCliCommand(\"start\", cliVersion),\n publicCliCommand(`setup ${retryFlags}`, cliVersion),\n ],\n details: {\n server,\n original: normalized.details,\n },\n });\n }\n}\n\nfunction defaultProjectName(cwd: string, framework: string): string {\n const fromDirectory = basename(cwd).trim();\n return fromDirectory.length > 0 ? fromDirectory : `zitadel-${framework}-app`;\n}\n\nfunction localSetupHint(error: unknown, retry: SetupRetryOptions, cliVersion: string): unknown {\n const normalized = toZitadelError(error);\n if (normalized.code !== \"E_LOCAL_SERVER_NOT_RUNNING\") {\n return error;\n }\n\n const setupCommand = `setup ${setupRetryFlags(retry)}`;\n\n return new ZitadelError(normalized.code, normalized.message, {\n hint:\n `${normalized.hint ? `${normalized.hint} ` : \"\"}` +\n \"Start local Zitadel first, then rerun setup. \" +\n \"After setup succeeds, follow its next_commands to start the app and verify registration, logout, and login in the browser.\",\n nextCommands: [\n publicCliCommand(\"start\", cliVersion),\n publicCliCommand(setupCommand, cliVersion),\n ],\n details: normalized.details,\n });\n}\n\n/** Renders an absolute path relative to `cwd` for human-readable output. */\nfunction relativeDisplay(cwd: string, path: string): string {\n return path.startsWith(cwd) ? path.slice(cwd.length + 1) : path;\n}\n\n/**\n * Replaces the user's `$HOME` with `~` in a path for compact terminal output.\n * Falls back to the raw path when `HOME` isn't set or doesn't match.\n */\nfunction shortPath(absolute: string): string {\n const home = process.env.HOME;\n if (home && absolute.startsWith(home)) {\n return `~${absolute.slice(home.length)}`;\n }\n return absolute;\n}\n\n/**\n * Picks one written file by suffix so the corresponding INSTALLED row can\n * reference it without hard-coding the path the patcher chose. Returns\n * the first match; falls back to `undefined` when the patcher didn't\n * write that artifact (e.g. a renderer without a register page).\n */\nfunction pickWrittenFile(written: string[], suffix: string): string | undefined {\n return written.find((file) => file.endsWith(suffix));\n}\n\n/**\n * Translates a patcher-written path into a single sentence the user can\n * read at narration speed. Returns `null` for directories and other\n * scaffolding artefacts that aren't worth narrating individually — the\n * file count in the closing `success(...)` and the summary's INSTALLED\n * section already cover them. The verb tense flips for `--dry-run` so\n * the user sees a preview (\"Would write ...\") instead of a claim that\n * something happened.\n */\nfunction describeWrittenFile(relPath: string, dryRun: boolean): string | null {\n // Mkdir ops surface in `filesWritten` alongside actual file writes.\n // They're noise at the per-step layer (the files inside them get\n // narrated on their own lines), so swallow them here.\n if (\n relPath === \".zitadel\" ||\n relPath === \".zitadel/flows\" ||\n relPath === \".zitadel/schemas\" ||\n relPath === \".zitadel/meta\"\n ) {\n return null;\n }\n const verb = dryRun ? \"Would write\" : \"Wrote\";\n const sentence = SENTENCE_BY_PATH[relPath];\n if (sentence) {\n return `${verb} ${sentence.subject} (${stylePath(relPath)})`;\n }\n return `${verb} ${stylePath(relPath)}`;\n}\n\n/**\n * Map from the patcher's deterministic output paths to a short noun\n * phrase describing what the file is for. Anything not in the map falls\n * back to the bare path in the narration; add an entry here when a new\n * scaffolded file deserves a clearer label.\n */\nconst SENTENCE_BY_PATH: Record<string, { subject: string }> = {\n \".gitignore\": { subject: \"the project's .gitignore additions\" },\n \".zitadel/secret\": { subject: \"the local project secret\" },\n \"zitadel.json\": { subject: \"the Zitadel project configuration\" },\n \".env.example\": { subject: \"the .env example template\" },\n \".env.local\": { subject: \"the local development environment variables\" },\n \".zitadel/state.json\": { subject: \"the sync state file\" },\n \".zitadel/flows/default-login.json\": { subject: \"the editable default login flow\" },\n \".zitadel/flows/README.md\": { subject: \"the flows folder README\" },\n \".zitadel/schemas/default-human-user.json\": {\n subject: \"the editable default human user schema\",\n },\n \".zitadel/schemas/README.md\": { subject: \"the schemas folder README\" },\n \".zitadel/meta/flow-definition.json\": { subject: \"the flow dialect spec (editor $schema)\" },\n \".zitadel/meta/user-schema.json\": { subject: \"the user-schema dialect spec\" },\n \".zitadel/meta/user-property.json\": { subject: \"the user-property dialect spec\" },\n \"AGENTS.md\": { subject: \"the agent guidance (golden journey + config dialect)\" },\n \"README.md\": { subject: \"the README's Zitadel section\" },\n \"app/page.tsx\": { subject: \"the home page redirect\" },\n \"app/login/page.tsx\": { subject: \"the login page\" },\n \"app/register/page.tsx\": { subject: \"the registration page\" },\n \"app/profile/page.tsx\": { subject: \"the profile page\" },\n \"middleware.ts\": { subject: \"the Next.js middleware\" },\n \"proxy.ts\": { subject: \"the Next.js proxy\" },\n \"custom-elements.d.ts\": { subject: \"the web-component type declarations\" },\n \"package.json\": { subject: \"package.json with the SDK dependency\" },\n};\n\n/** Builds the section list driving {@link renderSummary} for the setup command. */\nfunction buildSummary(opts: {\n projectFacts: Awaited<ReturnType<typeof detectProjectFacts>>;\n writtenRel: string[];\n project: CreateProject201;\n server: string;\n issuer: string;\n scaffoldedFramework: boolean;\n}): Section[] {\n const { projectFacts, writtenRel, project, server, issuer, scaffoldedFramework } = opts;\n const sdkPackage = \"@zitadel/sdk-next\";\n const packageJsonHit = pickWrittenFile(writtenRel, \"package.json\");\n\n const detected: Row[] = [{ label: \"Framework\", value: formatFrameworkLine(projectFacts) }];\n if (scaffoldedFramework) {\n detected.push({ label: \"Scaffold\", value: \"fresh project (no existing files)\" });\n }\n\n const installedRows: Row[] = [];\n if (packageJsonHit) {\n installedRows.push({\n label: \"Package\",\n value: sdkPackage,\n secondary: stylePath(fileNameOf(packageJsonHit)),\n });\n }\n for (const [label, suffix] of [\n [\"Home redirect\", \"app/page.tsx\"],\n [\"Login page\", \"app/login/page.tsx\"],\n [\"Register page\", \"app/register/page.tsx\"],\n [\"Profile page\", \"app/profile/page.tsx\"],\n [\"Request proxy\", \"proxy.ts\"],\n [\"Middleware\", \"middleware.ts\"],\n [\"Env vars\", \".env.local\"],\n ] as const) {\n const hit = pickWrittenFile(writtenRel, suffix);\n if (hit) installedRows.push({ label, value: stylePath(hit) });\n }\n\n const projectRows: Row[] = [\n { label: \"Project id\", value: styleId(project.id) },\n { label: \"Server\", value: styleUrl(server) },\n { label: \"App will run\", value: styleUrl(issuer) },\n ];\n\n return [\n { title: \"Detected\", rows: detected },\n { title: \"Installed\", rows: installedRows },\n { title: \"Project\", rows: projectRows },\n ];\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"setup.mjs","names":["relativeDisplay","stylePath","styleId","styleUrl","styleDim"],"sources":["../../src/lib/orca/patchers/posture.ts","../../src/lib/setup-resources.ts","../../src/commands/setup/install.ts","../../src/commands/setup/prompts/cancel.ts","../../src/commands/setup/prompts/design.ts","../../src/commands/setup/prompts/dev-port.ts","../../src/commands/setup/prompts/framework-confirm.ts","../../src/commands/setup/prompts/server.ts","../../src/commands/setup/prompts/sign-in-preset.ts","../../src/commands/setup/prompts/use-case.ts","../../src/commands/setup/prompts/pick-framework.ts","../../src/commands/setup/prompts/index.ts","../../src/commands/setup/summary.ts","../../src/commands/setup/index.ts"],"sourcesContent":["import type { ScaffoldPosture } from \"../../sync/types\";\n\n/**\n * Frameworks whose patchers add route files without owning the app shell —\n * the only ones where a pre-existing app keeps a layout for the widget\n * posture to inherit (ADR 044). The SPA families write the app's root\n * component, so nothing survives for a widget to embed into; they keep the\n * page posture until a non-destructive route/layout insertion contract\n * exists for their routers.\n */\nconst ROUTE_BASED_FRAMEWORKS: ReadonlySet<string> = new Set([\"next\", \"nuxt\"]);\n\n/**\n * The default embedding posture of the scaffolded auth/profile pages\n * (ADR 044), derived from the same hinge as the framework homepage: whether\n * setup created the app skeleton itself. A fresh scaffold has no design to\n * respect — full-page chrome is the strongest start. A pre-existing\n * route-based app has its own shell and theme, so the pages embed\n * `variant=\"widget\"` cards in a layout-neutral wrapper instead of painting\n * token-colored chrome underneath the host layout.\n *\n * Derived once at setup time and recorded in the scaffold manifest;\n * `doctor --fix` restores from the record rather than re-deriving (a\n * manifest-less legacy scaffold could not answer the hinge).\n */\nexport function derivePosture(frameworkId: string, scaffoldedFramework: boolean): ScaffoldPosture {\n if (!ROUTE_BASED_FRAMEWORKS.has(frameworkId)) {\n return \"page\";\n }\n return scaffoldedFramework ? \"page\" : \"widget\";\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport { consola } from \"consola\";\n\nimport type {\n CreateBranding201,\n CreateBrandingBody,\n CreateFlowDefinition201,\n CreateSchema201,\n CreateSchemaBody,\n} from \"@zitadel/api/generated/model\";\nimport type { ZitadelClient } from \"@zitadel/api/client\";\nimport {\n DEFAULT_BRANDING_CONFIG_PATH,\n DEFAULT_BRANDING_TEMPLATE_PATH,\n DEFAULT_FLOW_CONFIG_PATH,\n DEFAULT_FLOW_SCHEMA_URI,\n DEFAULT_SCHEMA_CONFIG_PATH,\n DEFAULT_SETUP_PRESET,\n DEFAULT_SETUP_USE_CASE,\n brandingReadmeContent,\n flowsReadmeContent,\n getDefaultBrandingConfig,\n getDefaultHumanUserSchema,\n getDefaultLoginFlow,\n schemasReadmeContent,\n type SetupPreset,\n type SetupUseCase,\n} from \"@zitadel/config/defaults\";\nimport { BRANDING_FILE_SCHEMA_REF } from \"@zitadel/config/meta-schemas\";\n\nimport { normalizeFlowBody, normalizeSchemaBody } from \"@zitadel/config/normalize\";\n\nimport { BRANDING_DIR, toBrandingWireBody } from \"./branding\";\nimport { FLOWS_DIR } from \"./flows\";\nimport { stableStringify } from \"./json\";\nimport { normalizePublicCliProse } from \"./public-cli\";\nimport { hashForState, writeBackResource } from \"./sync\";\nimport { updateState } from \"./sync/state\";\nimport { SCHEMAS_DIR } from \"./user-schema\";\nimport { ZitadelError } from \"./errors\";\n\nexport type MaterializeSetupResourcesResult = {\n filesWritten: string[];\n};\n\n/**\n * Scaffolds the versioned local default resources for a new project, uploads\n * them through the schema/flow APIs, and seeds `.zitadel/state.json` with the\n * IDs, hashes, and flow metadata the sync engine expects. Setup calls this only\n * after the framework patcher has created `.zitadel/{flows,schemas}` and the\n * initial state file.\n *\n * The schema is uploaded without an `$id`: the server assigns an opaque id on\n * `POST /schemas`, and the flow file can only be rendered after that id comes\n * back because `flow_definition.user_schema` must reference it.\n */\nexport async function materializeSetupResources(opts: {\n cwd: string;\n client: ZitadelClient;\n projectId: string;\n force: boolean;\n /** Sign-in preset (flow + auth methods) to scaffold; defaults to password-first. */\n preset?: SetupPreset;\n /** Use case (schema field set) to scaffold; defaults to minimal. */\n useCase?: SetupUseCase;\n /**\n * Login design to eject into `.zitadel/branding/` and publish as branding\n * revision 1. When absent, no branding files are scaffolded and the login\n * renders the built-in template (the `branding eject` command opts in later).\n */\n design?: string;\n /**\n * CLI version used to render `zitadel …` command mentions in the scaffolded\n * READMEs as runnable `npx @zitadel/cli@<version> …` commands — the CLI is\n * not a dependency of the generated app, so the bare command doesn't exist\n * there.\n */\n cliVersion: string;\n}): Promise<MaterializeSetupResourcesResult> {\n await mkdir(join(opts.cwd, FLOWS_DIR), { recursive: true });\n await mkdir(join(opts.cwd, SCHEMAS_DIR), { recursive: true });\n\n const filesWritten: string[] = [];\n const preset = opts.preset ?? DEFAULT_SETUP_PRESET;\n const useCase = opts.useCase ?? DEFAULT_SETUP_USE_CASE;\n\n const { $id: _templateId, ...schemaBody } = getDefaultHumanUserSchema({ preset, useCase }) as {\n $id?: string;\n } & Record<string, unknown>;\n void _templateId;\n\n const schemaWritten = await writeResourceFile(\n opts.cwd,\n DEFAULT_SCHEMA_CONFIG_PATH,\n schemaBody,\n opts.force,\n );\n if (schemaWritten) {\n filesWritten.push(join(opts.cwd, DEFAULT_SCHEMA_CONFIG_PATH));\n }\n\n const schema = (await opts.client.createSchema(schemaBody as CreateSchemaBody, {\n project_id: opts.projectId,\n })) as CreateSchema201;\n const schemaId = requiredString(schema.id, \"created schema id\");\n // Reconcile the just-written file with the server's stored body so local\n // config matches live state from the first second; a fetch failure keeps\n // the template body and its hash (parity is best-effort at setup).\n let schemaHash = hashForState({ normalize: normalizeSchemaBody }, schemaBody);\n try {\n const canonical = (await opts.client.getSchemaById(\n encodeURIComponent(schemaId),\n )) as object;\n const written = await writeBackResource(\n opts.cwd,\n DEFAULT_SCHEMA_CONFIG_PATH,\n { normalize: normalizeSchemaBody },\n canonical,\n );\n schemaHash = written.hash;\n } catch (err) {\n consola.debug(`fetch created schema ${schemaId} during setup failed:`, err);\n }\n await updateState(opts.cwd, DEFAULT_SCHEMA_CONFIG_PATH, {\n id: schemaId,\n hash: schemaHash,\n });\n\n const flowBody = getDefaultLoginFlow({ userSchemaUrl: schemaId, preset, useCase });\n\n const flowWritten = await writeResourceFile(\n opts.cwd,\n DEFAULT_FLOW_CONFIG_PATH,\n flowBody,\n opts.force,\n );\n if (flowWritten) {\n filesWritten.push(join(opts.cwd, DEFAULT_FLOW_CONFIG_PATH));\n }\n\n const flow = (await opts.client.createFlowDefinition({\n project_id: opts.projectId,\n schema_uri: DEFAULT_FLOW_SCHEMA_URI,\n flow_definition: flowBody,\n })) as CreateFlowDefinition201;\n\n let flowHash = hashForState({ normalize: normalizeFlowBody }, flowBody);\n if (flow.flow_definition) {\n const written = await writeBackResource(\n opts.cwd,\n DEFAULT_FLOW_CONFIG_PATH,\n { normalize: normalizeFlowBody, normalizeWrite: normalizeFlowBody },\n flow.flow_definition as object,\n );\n flowHash = written.hash;\n }\n await updateState(opts.cwd, DEFAULT_FLOW_CONFIG_PATH, {\n id: requiredString(flow.id, \"created flow definition id\"),\n hash: flowHash,\n name: flowBody.name,\n status: flowBody.status,\n });\n\n if (opts.design) {\n await mkdir(join(opts.cwd, BRANDING_DIR), { recursive: true });\n const { branding, template } = getDefaultBrandingConfig(opts.design);\n const descriptor = { $schema: BRANDING_FILE_SCHEMA_REF, ...branding };\n\n if (await writeResourceFile(opts.cwd, DEFAULT_BRANDING_CONFIG_PATH, descriptor, opts.force)) {\n filesWritten.push(join(opts.cwd, DEFAULT_BRANDING_CONFIG_PATH));\n }\n if (await writeRawFile(opts.cwd, DEFAULT_BRANDING_TEMPLATE_PATH, template, opts.force)) {\n filesWritten.push(join(opts.cwd, DEFAULT_BRANDING_TEMPLATE_PATH));\n }\n\n const brandingNormalize = (data: object): object => toBrandingWireBody(opts.cwd, data);\n const created = (await opts.client.createBranding(\n brandingNormalize(descriptor) as CreateBrandingBody,\n { project_id: opts.projectId },\n )) as CreateBranding201;\n await updateState(opts.cwd, DEFAULT_BRANDING_CONFIG_PATH, {\n id: requiredString(created.id, \"created branding revision id\"),\n hash: hashForState({ normalize: brandingNormalize }, descriptor),\n });\n\n const brandingReadme = join(BRANDING_DIR, \"README.md\");\n if (\n await writeReadmeFile(\n opts.cwd,\n brandingReadme,\n normalizePublicCliProse(brandingReadmeContent(), opts.cliVersion),\n )\n ) {\n filesWritten.push(join(opts.cwd, brandingReadme));\n }\n }\n\n const schemasReadme = join(SCHEMAS_DIR, \"README.md\");\n const flowsReadme = join(FLOWS_DIR, \"README.md\");\n if (\n await writeReadmeFile(\n opts.cwd,\n schemasReadme,\n normalizePublicCliProse(schemasReadmeContent(), opts.cliVersion),\n )\n ) {\n filesWritten.push(join(opts.cwd, schemasReadme));\n }\n if (\n await writeReadmeFile(\n opts.cwd,\n flowsReadme,\n normalizePublicCliProse(flowsReadmeContent(), opts.cliVersion),\n )\n ) {\n filesWritten.push(join(opts.cwd, flowsReadme));\n }\n\n return { filesWritten };\n}\n\n/**\n * Write a non-JSON scaffold file (the `.liquid` template) with the same\n * conflict semantics as {@link writeResourceFile}: `--force` overwrites,\n * otherwise an existing file is an `E_CONFLICT`.\n */\nasync function writeRawFile(\n cwd: string,\n relPath: string,\n content: string,\n force: boolean,\n): Promise<boolean> {\n const dest = join(cwd, relPath);\n await mkdir(dirname(dest), { recursive: true });\n try {\n await writeFile(dest, content, force ? undefined : { flag: \"wx\" });\n return true;\n } catch (error) {\n if (isErrno(error, \"EEXIST\")) {\n throw new ZitadelError(\"E_CONFLICT\", `${relPath} already exists`, {\n hint: \"Move the file aside or rerun setup with --force if you want setup to replace it.\",\n });\n }\n throw error;\n }\n}\n\n/**\n * Write a README file, but never overwrite an existing one. A developer who\n * has edited the README should keep their edits when `setup --force` is\n * re-run.\n */\nasync function writeReadmeFile(\n cwd: string,\n relPath: string,\n content: string,\n): Promise<boolean> {\n const dest = join(cwd, relPath);\n await mkdir(dirname(dest), { recursive: true });\n try {\n await writeFile(dest, content, { flag: \"wx\" });\n return true;\n } catch (error) {\n if (isErrno(error, \"EEXIST\")) {\n return false;\n }\n throw error;\n }\n}\n\nasync function writeResourceFile(\n cwd: string,\n relPath: string,\n body: object,\n force: boolean,\n): Promise<boolean> {\n const contents = `${stableStringify(body)}\\n`;\n try {\n await writeFile(join(cwd, relPath), contents, force ? undefined : { flag: \"wx\" });\n return true;\n } catch (error) {\n if (isErrno(error, \"EEXIST\")) {\n throw new ZitadelError(\"E_CONFLICT\", `${relPath} already exists`, {\n hint: \"Move the file aside or rerun setup with --force if you want setup to replace it.\",\n });\n }\n throw error;\n }\n}\n\nfunction requiredString(value: unknown, label: string): string {\n if (typeof value === \"string\" && value.length > 0) {\n return value;\n }\n throw new ZitadelError(\"E_VALIDATION\", `Missing ${label} in server response.`);\n}\n\nfunction isErrno(error: unknown, code: string): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n (error as NodeJS.ErrnoException).code === code\n );\n}\n","import { consola } from \"consola\";\n\nimport { ZitadelError } from \"../../lib/errors\";\nimport { customizeAndPublishActions, verifyLoginAction } from \"../../lib/journey-guidance\";\nimport {\n detectPackageManager,\n devCommandFor,\n installCommandFor,\n runPackageCommand,\n type PackageCommand,\n type PackageManager,\n} from \"../../lib/package-manager\";\nimport { publicCliCommand } from \"../../lib/public-cli\";\n\ntype InstallReason = \"dry-run\" | \"skip-install\" | \"no-dependency-changes\";\n\nexport type SetupInstall = {\n status: \"completed\" | \"skipped\" | \"not-needed\";\n package_manager: PackageManager;\n command: string;\n reason?: InstallReason;\n};\n\nexport type SetupInstallOutcome = {\n install: SetupInstall;\n devCommand: string;\n /**\n * Journey-staged subset for the human terminal box: the verify mission\n * plus one breadcrumb to `status`/README. Customize/publish guidance stays\n * out until login demonstrably works (Elina, alpha.15).\n */\n boxActions: string[];\n /** Complete journey for the JSON envelope — agents consume all of it. */\n nextActions: string[];\n nextCommands: string[];\n};\n\nexport type SetupInstallInput = {\n cliVersion: string;\n cwd: string;\n depsAdded: ReadonlyArray<string>;\n dryRun: boolean;\n env: NodeJS.ProcessEnv;\n issuer: string;\n json: boolean;\n scaffoldedFramework: boolean;\n skipInstall: boolean;\n run?: typeof runPackageCommand;\n};\n\nexport async function installDependenciesForSetup(\n input: SetupInstallInput,\n): Promise<SetupInstallOutcome> {\n const packageManager = await detectPackageManager(input.cwd);\n const installCommand = installCommandFor(packageManager);\n const devCommand = devCommandFor(packageManager);\n const needsInstall = input.scaffoldedFramework || input.depsAdded.length > 0;\n\n if (!needsInstall) {\n return outcome({\n install: {\n status: \"not-needed\",\n package_manager: packageManager,\n command: installCommand.display,\n reason: \"no-dependency-changes\",\n },\n devCommand: devCommand.display,\n cliVersion: input.cliVersion,\n issuer: input.issuer,\n includeInstallCommand: false,\n });\n }\n\n if (input.dryRun || input.skipInstall) {\n return outcome({\n install: {\n status: \"skipped\",\n package_manager: packageManager,\n command: installCommand.display,\n reason: input.dryRun ? \"dry-run\" : \"skip-install\",\n },\n devCommand: devCommand.display,\n cliVersion: input.cliVersion,\n issuer: input.issuer,\n includeInstallCommand: true,\n });\n }\n\n consola.start(`Installing dependencies with ${installCommand.display}`);\n try {\n await (input.run ?? runPackageCommand)(installCommand, {\n cwd: input.cwd,\n env: input.env,\n redirectStdoutToStderr: input.json,\n });\n } catch (error) {\n throw installFailed(error, installCommand, devCommand, input.cwd);\n }\n consola.success(\"Installed dependencies\");\n\n return outcome({\n install: {\n status: \"completed\",\n package_manager: packageManager,\n command: installCommand.display,\n },\n devCommand: devCommand.display,\n cliVersion: input.cliVersion,\n issuer: input.issuer,\n includeInstallCommand: false,\n });\n}\n\nfunction outcome(input: {\n install: SetupInstall;\n devCommand: string;\n cliVersion: string;\n issuer: string;\n includeInstallCommand: boolean;\n}): SetupInstallOutcome {\n const planCommand = publicCliCommand(\"plan\", input.cliVersion);\n const statusCommand = publicCliCommand(\"status\", input.cliVersion);\n const verifyActions = [\n ...(input.includeInstallCommand ? [`Install dependencies: ${input.install.command}`] : []),\n `Start your project: ${input.devCommand} (then open ${input.issuer}/login)`,\n verifyLoginAction(),\n ];\n const breadcrumb = `Once login works: ${statusCommand} shows your next steps; customizing is covered in your README's Zitadel section.`;\n return {\n install: input.install,\n devCommand: input.devCommand,\n boxActions: [...verifyActions, breadcrumb],\n nextActions: [...verifyActions, ...customizeAndPublishActions(input.cliVersion)],\n nextCommands: input.includeInstallCommand\n ? [input.install.command, input.devCommand, planCommand]\n : [input.devCommand, planCommand],\n };\n}\n\nfunction installFailed(\n error: unknown,\n installCommand: PackageCommand,\n devCommand: PackageCommand,\n cwd: string,\n): ZitadelError {\n return new ZitadelError(\"E_VALIDATION\", `Dependency install failed: ${installCommand.display}`, {\n hint: `Run ${installCommand.display} in ${cwd}, then start the app with ${devCommand.display}.`,\n nextCommands: [installCommand.display],\n details: { command: installCommand.display, cwd, original: errorShape(error) },\n });\n}\n\nfunction errorShape(error: unknown): Record<string, unknown> {\n if (error instanceof Error) {\n return {\n name: error.name,\n message: error.message,\n code: (error as NodeJS.ErrnoException).code,\n };\n }\n return { message: String(error) };\n}\n","import { cancel, isCancel } from \"@clack/prompts\";\n\nimport { ZitadelError } from \"../../../lib/errors\";\n\n/**\n * Converts a clack cancellation (Ctrl-C) into a thrown `E_VALIDATION` rather\n * than a partial answer. Every prompt funnels its clack return value through\n * this so the wizard never proceeds with a sentinel or missing value.\n */\nexport function bail<T>(value: T | symbol): asserts value is T {\n if (isCancel(value)) {\n cancel(\"Setup cancelled.\");\n throw new ZitadelError(\"E_VALIDATION\", \"Setup cancelled by user\");\n }\n}\n","import { select } from \"@clack/prompts\";\n\nimport { BRANDING_DESIGNS, type BrandingDesign } from \"@zitadel/config/defaults\";\n\nimport { BRANDING_DESIGN_INFO } from \"../../../lib/branding/designs\";\n\nimport { bail } from \"./cancel\";\nimport type { PromptContext, SetupAnswers, SetupPrompt } from \"./types\";\n\n/**\n * Sentinel select value for \"keep the built-in login\" — clack option values\n * must be strings, and `undefined` in {@link SetupAnswers.design} is the\n * real representation of that choice.\n */\nconst BUILT_IN = \"built-in\";\n\n/**\n * \"How should the login look?\" — the last wizard question (#676). Asks after\n * the sign-in preset so the order tells a story: the use case owns what is\n * collected, the preset owns how users authenticate, the design owns how\n * that experience looks.\n *\n * The built-in default is preselected and writes nothing. Picking a starter\n * design forks its Liquid template into `.zitadel/branding/` and publishes\n * it as branding revision 1 — from then on the template is repo-owned and\n * stops tracking built-in improvements, so the option labels make the\n * file-write explicit and keep ownership an opt-in. `--design` is\n * authoritative; non-interactive runs keep the built-in template.\n */\nexport class DesignPrompt implements SetupPrompt {\n async ask(answers: SetupAnswers, ctx: PromptContext): Promise<SetupAnswers> {\n if (ctx.designFromFlag) {\n return answers;\n }\n const value = await select({\n message:\n \"How should the login look? A starter design adds its editable template to .zitadel/branding/.\",\n initialValue: (answers.design as string | undefined) ?? BUILT_IN,\n options: [\n {\n value: BUILT_IN,\n label: \"Built-in\",\n hint: \"no files added; pick a design anytime later with `branding eject`\",\n },\n ...BRANDING_DESIGNS.map((design) => ({\n value: design as string,\n label: BRANDING_DESIGN_INFO[design].label,\n hint: BRANDING_DESIGN_INFO[design].hint,\n })),\n ],\n });\n bail(value);\n if (value === BUILT_IN) {\n return { ...answers, design: undefined };\n }\n return { ...answers, design: value as BrandingDesign };\n }\n}\n","import { text } from \"@clack/prompts\";\n\nimport { bail } from \"./cancel\";\nimport type { PromptContext, SetupAnswers, SetupPrompt } from \"./types\";\n\n/**\n * \"Dev server port\" — defaults to the detected port. The validated answer\n * becomes the issuer URL (`http://localhost:<port>`) via `issuerFromPort`.\n */\nexport class DevPortPrompt implements SetupPrompt {\n async ask(answers: SetupAnswers, ctx: PromptContext): Promise<SetupAnswers> {\n // `--dev-port <n>` is authoritative: skip the prompt so an interactive\n // answer can't override the explicit flag (the base command already folded\n // it into answers.devPort).\n if (ctx.devPortFromFlag) {\n return answers;\n }\n const value = await text({\n message: \"Dev server port\",\n placeholder: String(answers.devPort),\n initialValue: String(answers.devPort),\n validate: (input) => {\n const num = Number.parseInt(input ?? \"\", 10);\n return Number.isFinite(num) && num > 0 && num < 65536\n ? undefined\n : \"Must be a port number\";\n },\n });\n bail(value);\n return { ...answers, devPort: Number.parseInt(String(value), 10) };\n }\n}\n","import { confirm } from \"@clack/prompts\";\n\nimport { ZitadelError } from \"../../../lib/errors\";\nimport { bail } from \"./cancel\";\nimport type { PromptContext, SetupAnswers, SetupPrompt } from \"./types\";\n\n/**\n * \"Detected `<framework>`. Proceed?\" — the wizard's first question. Accepting\n * leaves answers unchanged; declining throws `E_UNSUPPORTED_PROJECT_SHAPE`\n * (the user should re-run with an explicit `--framework`).\n */\nexport class FrameworkConfirmPrompt implements SetupPrompt {\n async ask(answers: SetupAnswers, ctx: PromptContext): Promise<SetupAnswers> {\n const ack = await confirm({\n message: `Detected ${ctx.framework.id}. Proceed?`,\n initialValue: true,\n });\n bail(ack);\n if (ack === false) {\n throw new ZitadelError(\n \"E_UNSUPPORTED_PROJECT_SHAPE\",\n \"Setup cancelled — framework declined\",\n { hint: `Re-run with --framework ${ctx.framework.id} when ready.` },\n );\n }\n return answers;\n }\n}\n","import { select, spinner, text } from \"@clack/prompts\";\n\nimport { detectHealthyLocalServer } from \"../../../lib/local-server/runtime\";\nimport { DEFAULT_SERVER } from \"../../../lib/server\";\nimport { bail } from \"./cancel\";\nimport type { PromptContext, SetupAnswers, SetupPrompt } from \"./types\";\n\n/** Sentinel returned by the choice select when the user picks \"Custom URL\". */\nconst CUSTOM = \"__custom__\";\n\n/**\n * \"Which server should `zitadel.json` point to?\" — Zitadel Cloud, the managed\n * local server we detected, or a custom URL.\n *\n * Before asking, it looks for a healthy local Zitadel server the same way the\n * rest of the CLI does (`detectHealthyLocalServer`: the runtime metadata that\n * `zitadel start` wrote to `.zitadel/local/runtime.json`, falling back to a\n * `/healthz` probe on the default localhost port). A detected server becomes\n * an extra option in the choice list *and* the preselected answer — a user\n * who just ran `zitadel start` almost certainly wants it, and `start`'s own\n * next-step hint says `setup --server local`. Picking it writes the URL\n * directly to `answers.server`; picking \"Custom URL\" still asks for a\n * validated URL exactly as before.\n */\nexport class ServerPrompt implements SetupPrompt {\n async ask(answers: SetupAnswers, ctx: PromptContext): Promise<SetupAnswers> {\n // `--server <url>` overrides the wizard entirely. The base command\n // already validated and resolved the URL into `answers.server`;\n // asking the user to re-pick from a fixed select list when their\n // flag isn't in the list (Cloud / detected / Custom) was a bug —\n // clack would silently default back to Cloud.\n if (ctx.serverFlag) {\n return answers;\n }\n const detected = await detectLocalServer(ctx.cwd);\n\n const choice = await select({\n message: \"Which server should zitadel.json point to?\",\n options: [\n {\n value: DEFAULT_SERVER,\n label: \"Zitadel Cloud (api.zitadel.cloud)\",\n hint: \"recommended for real projects\",\n },\n ...(detected\n ? [\n {\n value: detected,\n label: `Local Zitadel server (${detected})`,\n hint: \"detected — started with zitadel start\",\n },\n ]\n : []),\n { value: CUSTOM, label: \"Custom URL (self-hosted)\" },\n ],\n initialValue: detected ?? answers.server ?? DEFAULT_SERVER,\n });\n bail(choice);\n if (choice !== CUSTOM) {\n return { ...answers, server: choice as string };\n }\n const custom = await text({\n message: \"Server URL\",\n placeholder: \"https://zitadel.internal\",\n validate: (value) => {\n try {\n new URL(value ?? \"\");\n return;\n } catch {\n return \"Must be a valid URL\";\n }\n },\n });\n bail(custom);\n return { ...answers, server: custom as string };\n }\n}\n\n/**\n * Wraps {@link detectHealthyLocalServer} in a spinner: the unhealthy paths\n * block on up to two 1.5s `/healthz` probes, long enough that the wizard\n * should say what it is doing.\n */\nasync function detectLocalServer(cwd: string): Promise<string | undefined> {\n const s = spinner();\n s.start(\"Checking for a local Zitadel server\");\n const detected = await detectHealthyLocalServer(cwd);\n s.stop(\n detected\n ? `Found local Zitadel server at ${detected}.`\n : \"No local Zitadel server detected.\",\n );\n return detected;\n}\n","import { select } from \"@clack/prompts\";\n\nimport { SETUP_PRESETS, type SetupPreset } from \"@zitadel/config/defaults\";\n\nimport { bail } from \"./cancel\";\nimport type { PromptContext, SetupAnswers, SetupPrompt } from \"./types\";\n\n/**\n * \"How should users sign in?\" — picks the schema+flow preset the scaffold\n * starts from (#448: app-type/preset selection before any `.zitadel/` file\n * is written). `--preset` is authoritative; non-interactive runs keep the\n * password-first default seeded by the command.\n */\nexport class SignInPresetPrompt implements SetupPrompt {\n async ask(answers: SetupAnswers, ctx: PromptContext): Promise<SetupAnswers> {\n if (ctx.presetFromFlag) {\n return answers;\n }\n const labels: Record<SetupPreset, string> = {\n \"password-first\": \"Password first — email + password, passkey optional during registration\",\n \"passkey-first\": \"Passkey first — one-tap passkey up front, email + password fallback\",\n };\n const value = await select({\n message: \"How should users sign in?\",\n initialValue: answers.preset,\n options: SETUP_PRESETS.map((preset) => ({ value: preset, label: labels[preset] })),\n });\n bail(value);\n return { ...answers, preset: value as SetupPreset };\n }\n}\n","import { select } from \"@clack/prompts\";\n\nimport { SETUP_USE_CASES, type SetupUseCase } from \"@zitadel/config/defaults\";\n\nimport { bail } from \"./cancel\";\nimport type { PromptContext, SetupAnswers, SetupPrompt } from \"./types\";\n\n/**\n * \"Who will sign in to your app?\" — picks the use case, which owns the\n * schema field set the scaffold collects (#448). Orthogonal to the sign-in\n * preset, so this asks first: what a user *is* before *how* they sign in.\n * `--use-case` is authoritative; non-interactive runs keep the minimal\n * default seeded by the command.\n */\nexport class UseCasePrompt implements SetupPrompt {\n async ask(answers: SetupAnswers, ctx: PromptContext): Promise<SetupAnswers> {\n if (ctx.useCaseFromFlag) {\n return answers;\n }\n // Audience-first labels (the use case is recorded in `zitadel.json` and may\n // inform guidance/status beyond the schema, so it stays generic), with the\n // collected fields as a dimmed per-option hint. The message notes the fields\n // stay editable after setup — the scaffolded schema/flow are the source of\n // truth.\n const options: Record<SetupUseCase, { label: string; hint: string }> = {\n minimal: { label: \"Just me or a small group\", hint: \"collects email\" },\n consumer: { label: \"Consumers\", hint: \"collects email, given & family name\" },\n business: { label: \"Business\", hint: \"collects email, given & family name, company\" },\n };\n const value = await select({\n message: \"Who will sign in to your app? Collected fields stay editable after setup.\",\n initialValue: answers.useCase,\n options: SETUP_USE_CASES.map((useCase) => ({\n value: useCase,\n label: options[useCase].label,\n hint: options[useCase].hint,\n })),\n });\n bail(value);\n return { ...answers, useCase: value as SetupUseCase };\n }\n}\n","import { intro, select } from \"@clack/prompts\";\n\nimport { bail } from \"./cancel\";\n\n/**\n * \"Choose a framework to scaffold\" — the only prompt outside the main wizard.\n * Runs at the empty-directory branch (before any other detection), so it owns\n * its own `intro` heading. Returns the chosen framework id; choices come from\n * `Orca.availableFrameworks`.\n */\nexport class PickFrameworkPrompt {\n async ask(\n choices: ReadonlyArray<{ id: string; displayName: string }>,\n ): Promise<string> {\n intro(\"Zitadel setup — new project\");\n const picked = await select({\n message: \"Choose a framework to scaffold\",\n options: choices.map((choice) => ({ value: choice.id, label: choice.displayName })),\n });\n bail(picked);\n return picked as string;\n }\n}\n","/**\n * Public surface for the setup wizard prompts. The `setup` command imports\n * {@link SETUP_PROMPTS} and iterates every entry, threading the answers\n * through each prompt's `ask` so they decide whether to actually ask the\n * user. Add a new question by writing a class and appending an instance to\n * the registry below.\n *\n * {@link PickFrameworkPrompt} is intentionally **not** in {@link SETUP_PROMPTS}\n * — it runs at the empty-directory scaffold branch, before the main wizard\n * starts.\n */\nimport { DesignPrompt } from \"./design\";\nimport { DevPortPrompt } from \"./dev-port\";\nimport { FrameworkConfirmPrompt } from \"./framework-confirm\";\nimport { ServerPrompt } from \"./server\";\nimport { SignInPresetPrompt } from \"./sign-in-preset\";\nimport type { SetupPrompt } from \"./types\";\nimport { UseCasePrompt } from \"./use-case\";\n\nexport type { PromptContext, SetupAnswers, SetupPrompt } from \"./types\";\nexport { bail } from \"./cancel\";\nexport { DesignPrompt } from \"./design\";\nexport { DevPortPrompt } from \"./dev-port\";\nexport { FrameworkConfirmPrompt } from \"./framework-confirm\";\nexport { ServerPrompt } from \"./server\";\nexport { SignInPresetPrompt } from \"./sign-in-preset\";\nexport { UseCasePrompt } from \"./use-case\";\nexport { PickFrameworkPrompt } from \"./pick-framework\";\n\n/** Every question the main setup wizard asks, in ask order. */\nexport const SETUP_PROMPTS: ReadonlyArray<SetupPrompt> = [\n new FrameworkConfirmPrompt(),\n new ServerPrompt(),\n new DevPortPrompt(),\n new UseCasePrompt(),\n new SignInPresetPrompt(),\n new DesignPrompt(),\n];\n","import { readFile, stat } from \"node:fs/promises\";\nimport { basename, join } from \"node:path\";\n\nimport type { BrandingDesign } from \"@zitadel/config/defaults\";\nimport pc from \"picocolors\";\n\nimport { detectPackageManager, type PackageManager } from \"../../lib/package-manager\";\n\n/**\n * Structured end-of-command summary, modelled on the report layout the\n * setup mock specifies: one line per fact, grouped under uppercase section\n * headers, with consistent `✓ label value` formatting. Each {@link Row}\n * carries the label, the primary value (already styled by the caller),\n * and an optional `secondary` shown after a dim `→` to mirror the\n * \"package → file\" lines in the mock.\n */\nexport type Row = {\n label: string;\n value: string;\n secondary?: string;\n};\n\nexport type Section = {\n title: string;\n rows: Row[];\n};\n\n/**\n * Renders a path under `cwd` with stable POSIX separators. Setup's summary\n * matches generated artifacts against repository-style suffixes such as\n * `.zitadel/schemas/default-human-user.json`; normalizing here keeps those\n * matches working when Node returns Windows paths with backslashes.\n */\nexport function relativeDisplayPath(cwd: string, absolute: string): string {\n const boundary = absolute[cwd.length];\n const withinCwd = absolute.startsWith(cwd) && (boundary === \"/\" || boundary === \"\\\\\");\n const display = withinCwd ? absolute.slice(cwd.length + 1) : absolute;\n return display.replaceAll(\"\\\\\", \"/\");\n}\n\n/**\n * Renders the section list as a single multi-line string. Labels are\n * padded to a common width per section so the `✓ label value` columns\n * line up, the title prints in dim gray, and `✓` is green. Values come\n * in pre-styled — use the helpers below ({@link path}, {@link url},\n * {@link id}, {@link dim}) to keep the colour palette consistent with\n * the mock.\n */\nexport function renderSummary(sections: Section[]): string {\n const lines: string[] = [];\n for (const section of sections) {\n if (section.rows.length === 0) continue;\n if (lines.length > 0) lines.push(\"\");\n lines.push(pc.dim(section.title.toUpperCase()));\n const labelWidth = Math.max(...section.rows.map((r) => r.label.length)) + 3;\n for (const row of section.rows) {\n const labelCol = row.label.padEnd(labelWidth);\n const secondary = row.secondary ? ` ${pc.dim(\"→\")} ${row.secondary}` : \"\";\n lines.push(`${pc.green(\"✓\")} ${labelCol}${row.value}${secondary}`);\n }\n }\n return lines.join(\"\\n\");\n}\n\n/** Cyan, for filesystem paths the user can open. */\nexport const path = (s: string): string => pc.cyan(s);\n/** Cyan, for URLs (browser-clickable in most terminals). */\nexport const url = (s: string): string => pc.cyan(s);\n/** Yellow, for opaque ids the user shouldn't try to read. */\nexport const id = (s: string): string => pc.yellow(s);\n/** Dim, for separators and secondary detail. */\nexport const dim = (s: string): string => pc.dim(s);\n\n/**\n * Detected facts about the user's project, surfaced in the `DETECTED`\n * section. {@link detectProjectFacts} reads the on-disk markers (lock\n * file, tsconfig, framework dep version) without any platform call.\n */\nexport type ProjectFacts = {\n framework: string;\n frameworkVersion?: string;\n typescript: boolean;\n packageManager: PackageManager;\n};\n\n/**\n * Reads the project root to identify the framework version, TS presence,\n * and which package manager the user runs. Returns safe defaults (npm\n * fallback, no version) on any error so summary rendering can always proceed.\n */\nexport async function detectProjectFacts(cwd: string, frameworkId: string): Promise<ProjectFacts> {\n const facts: ProjectFacts = {\n framework: frameworkId,\n typescript: await fileExists(join(cwd, \"tsconfig.json\")),\n packageManager: await detectPackageManager(cwd),\n };\n try {\n const raw = await readFile(join(cwd, \"package.json\"), \"utf8\");\n const pj = JSON.parse(raw) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const depPkg = depFromFramework(frameworkId);\n const range = pj.dependencies?.[depPkg] ?? pj.devDependencies?.[depPkg];\n if (range) {\n facts.frameworkVersion = stripRange(range);\n }\n } catch {\n // Missing or unreadable package.json — version stays undefined; the\n // renderer skips that segment, which is the same as the user not\n // having declared the framework dep yet.\n }\n return facts;\n}\n\n/** Formats the project facts as the \"Next.js 15 · TypeScript · npm\" string the mock shows. */\nexport function formatFrameworkLine(facts: ProjectFacts): string {\n const segments: string[] = [];\n const pretty = prettyFramework(facts.framework);\n segments.push(facts.frameworkVersion ? `${pretty} ${facts.frameworkVersion}` : pretty);\n if (facts.typescript) segments.push(\"TypeScript\");\n segments.push(facts.packageManager);\n return segments.join(` ${pc.dim(\"·\")} `);\n}\n\nasync function fileExists(p: string): Promise<boolean> {\n try {\n await stat(p);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction depFromFramework(framework: string): string {\n switch (framework) {\n case \"next\":\n return \"next\";\n case \"nuxt\":\n return \"nuxt\";\n default:\n return framework;\n }\n}\n\nfunction prettyFramework(framework: string): string {\n switch (framework) {\n case \"next\":\n return \"Next.js\";\n case \"nuxt\":\n return \"Nuxt\";\n default:\n return framework;\n }\n}\n\n/** Strips `^`/`~`/`>=`/`v` prefixes from an npm range so the version reads cleanly in the summary. */\nfunction stripRange(range: string): string {\n const trimmed = range.replace(/^([\\^~]|>=?|v)/, \"\").trim();\n // Take the first dotted segment so multi-range strings (`^15.0.0 || ^14.0.0`)\n // collapse to a single readable version in the report.\n const first = trimmed.split(/\\s+/)[0];\n return first ?? trimmed;\n}\n\n/** Returns just the file name from a relative path, for the `→ filename` secondary detail in PACKAGE rows. */\nexport function fileNameOf(p: string): string {\n return basename(p);\n}\n\n/**\n * Layout caveats for the chosen login design, shown to humans after the\n * summary box and carried in the JSON envelope's `warnings`.\n *\n * The split family's brand pane is keyed to the **login's own container**\n * width — a `@container (max-width: 48rem)` query on the widget's mount, not\n * a viewport media query. Above that the pane renders; below it the pane is\n * `display: none` and the compact brand mark takes its place — and the split\n * template only emits that mark when `branding.json` names `logo_url` or\n * `hero_url`, so without one the narrow layout loses the branding entirely.\n *\n * Independent of posture, because the container query is: a full-page login\n * hits the same collapse on a phone that an embedded card hits in a sidebar.\n * Gating on `widget` would have been a guess about the container, and a wrong\n * one in both directions — the wrapper setup scaffolds for a widget is\n * full-width (the pane renders there), and a page-posture login on a phone is\n * exactly the narrow case the advice is for. `hero` stays quiet: its compact\n * fallback is editable text, so a narrow container never leaves it blank.\n */\nexport function designWarnings(design?: BrandingDesign): string[] {\n if (design !== \"split\" && design !== \"split-right\") {\n return [];\n }\n return [\n `The ${design} design shows its brand pane only when the login's container is wide; a narrow container — a card-width embed, or any phone-width viewport — collapses it to the compact brand mark. Set logo_url (or hero_url) in .zitadel/branding/branding.json so that mark isn't empty.`,\n ];\n}\n","import { rm } from \"node:fs/promises\";\nimport { basename, join } from \"node:path\";\n\nimport { intro, outro } from \"@clack/prompts\";\nimport { Flags } from \"@oclif/core\";\nimport { createZitadelClient } from \"@zitadel/api/client\";\nimport type { CreateProject201 } from \"@zitadel/api/generated/model\";\nimport {\n BRANDING_DESIGNS,\n DEFAULT_SETUP_PRESET,\n DEFAULT_SETUP_USE_CASE,\n SETUP_PRESETS,\n SETUP_USE_CASES,\n type BrandingDesign,\n type SetupPreset,\n type SetupUseCase,\n} from \"@zitadel/config/defaults\";\nimport { consola } from \"consola\";\n\nimport { brandingDesignLabel } from \"../../lib/branding/designs\";\nimport { claimAction, claimCommand, claimState } from \"../../lib/claim-state\";\nimport { toZitadelError, ZitadelError } from \"../../lib/errors\";\nimport { brandingGuidanceAction } from \"../../lib/journey-guidance\";\nimport { BaseCommand, type JsonEnvelope } from \"../../lib/oclif\";\nimport {\n createOrca,\n inspectScaffoldTarget,\n issuerFromPort,\n type FrameworkFacts,\n type Orca,\n type ScaffoldTarget,\n} from \"../../lib/orca\";\nimport {\n AVAILABLE_RENDERER_IDS,\n RENDERER_IDS,\n} from \"../../lib/orca/patchers/rule/next/renderers/registry\";\nimport type { PatchContext } from \"../../lib/orca/patchers/types\";\nimport { hasZitadelConfig, hasZitadelSecret } from \"../../lib/project\";\nimport { publicCliCommand } from \"../../lib/public-cli\";\nimport { derivePosture } from \"../../lib/orca/patchers/posture\";\nimport { writeScaffoldManifest } from \"../../lib/scaffold-manifest\";\nimport {\n materializeSetupResources,\n type MaterializeSetupResourcesResult,\n} from \"../../lib/setup-resources\";\nimport { installDependenciesForSetup } from \"./install\";\nimport { PickFrameworkPrompt, SETUP_PROMPTS, type SetupAnswers } from \"./prompts\";\nimport {\n designWarnings,\n detectProjectFacts,\n dim as styleDim,\n fileNameOf,\n formatFrameworkLine,\n id as styleId,\n path as stylePath,\n relativeDisplayPath as relativeDisplay,\n renderSummary,\n url as styleUrl,\n type Row,\n type Section,\n} from \"./summary\";\n\n/**\n * The frameworks `--framework` accepts, derived from Orca's registry so the\n * flag can't drift from what the CLI can actually scaffold. `createOrca` is\n * pure (it only builds the in-memory registries), so this is safe at module\n * load.\n */\nconst FRAMEWORK_OPTIONS = createOrca()\n .availableFrameworks()\n .map((framework) => framework.id);\n\n/**\n * `--renderer` offers only ids `getRenderer` will resolve: a\n * declared-but-unpublished renderer (ADR 006) keeps its registry entry to\n * reserve the id, but is surfaced as unavailable in the flag description\n * instead of in `options`, so `--help` never advertises a value that is\n * guaranteed to fail and an explicit pass is rejected at parse time — before\n * any remote project is created.\n */\nconst UNAVAILABLE_RENDERER_IDS = RENDERER_IDS.filter(\n (id) => !AVAILABLE_RENDERER_IDS.includes(id),\n);\nconst RENDERER_FLAG_DESCRIPTION =\n UNAVAILABLE_RENDERER_IDS.length === 0\n ? \"Renderer (default: react).\"\n : `Renderer (default: react). Not yet available: ${UNAVAILABLE_RENDERER_IDS.join(\", \")}.`;\n\n/** `zitadel setup` — create a project and scaffold local auth.\n *\n * Detects (or, for an empty directory, scaffolds then re-detects) the\n * framework, runs the wizard prompts to fill in any answers not pre-supplied\n * by flags, creates the remote project without server fallback defaults,\n * patches the local files via `Orca`'s framework patcher, then scaffolds and\n * uploads editable schema/flow config from `.zitadel/**`.\n *\n * Every interactive question lives in {@link SETUP_PROMPTS} (the main wizard\n * — each entry is a small class) and {@link PickFrameworkPrompt} (the\n * empty-directory framework choice, before the main wizard).\n */\nexport default class Setup extends BaseCommand {\n static override description = \"Create a Zitadel project and scaffold local auth.\";\n static override examples = [\n \"<%= config.bin %> setup --framework next\",\n \"<%= config.bin %> setup --framework react --dev-port 3000\",\n ];\n static override flags = {\n framework: Flags.string({ description: \"Framework to target.\", options: FRAMEWORK_OPTIONS }),\n renderer: Flags.string({\n description: RENDERER_FLAG_DESCRIPTION,\n options: [...AVAILABLE_RENDERER_IDS],\n }),\n \"dev-port\": Flags.integer({\n description:\n \"Dev-server port; also the issuer origin registered with Zitadel. Defaults to the detected port. Use distinct ports to run several scaffolded apps side by side.\",\n }),\n \"skip-install\": Flags.boolean({\n description: \"Do not install dependencies after setup updates package.json.\",\n }),\n preset: Flags.string({\n description:\n \"Sign-in preset for the scaffolded schema and login flow (default: password-first).\",\n options: [...SETUP_PRESETS],\n }),\n \"use-case\": Flags.string({\n description:\n \"Use case for the scaffolded schema fields: who signs in to the app (default: minimal).\",\n options: [...SETUP_USE_CASES],\n }),\n design: Flags.string({\n description:\n \"Login design to eject into .zitadel/branding/ and publish as branding revision 1. Skips the wizard's design question. When omitted in non-interactive runs, the login uses the built-in template; run the `branding eject` command later to customize. Split-family designs (split, split-right, hero) collapse their brand pane by container width: narrow containers — including widget-posture embeds at card width — render the compact brand mark instead (logo_url, else hero_url, from .zitadel/branding/branding.json; hero falls back to editable text).\",\n options: [...BRANDING_DESIGNS],\n }),\n };\n\n async run(): Promise<JsonEnvelope> {\n const { flags } = await this.parse(Setup);\n try {\n await this.toMeta(flags);\n } catch (error) {\n throw localSetupHint(error, retryOptionsFromFlags(flags), this.config.version);\n }\n const { cwd, nonInteractive, dryRun, force } = this.meta;\n\n if (await hasZitadelConfig(cwd)) {\n return this.emit({ status: \"skipped\", reason: \"already-initialized\" });\n }\n if (await hasZitadelSecret(cwd)) {\n throw new ZitadelError(\"E_CONFLICT\", \".zitadel/secret exists without zitadel.json\", {\n hint: \"Move the secret aside or restore zitadel.json before running setup.\",\n });\n }\n\n const orca = createOrca();\n\n consola.start(`Detecting framework in ${shortPath(cwd)}`);\n let framework: FrameworkFacts;\n let scaffoldedFramework = false;\n try {\n framework = await orca.detect(cwd, flags.framework);\n consola.success(\n `Detected ${framework.id}${framework.devPort ? ` (dev port ${framework.devPort})` : \"\"}`,\n );\n } catch (error) {\n if (\n error instanceof ZitadelError &&\n error.code === \"E_FRAMEWORK_NOT_DETECTED\"\n ) {\n const target = await inspectScaffoldTarget(cwd);\n if (!target.scaffoldable) {\n throw frameworkDetectionWithScaffoldTarget(error, cwd, target);\n }\n consola.info(\"Fresh app directory — scaffolding a fresh project\");\n framework = await orca.scaffold(\n cwd,\n await resolveScaffoldFramework(flags.framework, nonInteractive, orca),\n );\n scaffoldedFramework = true;\n consola.success(`Scaffolded ${framework.id} skeleton`);\n } else {\n throw error;\n }\n }\n\n this.recordTelemetry({\n framework: framework.id,\n renderer: flags.renderer ?? \"react\",\n scaffolded_skeleton: scaffoldedFramework,\n skip_install: Boolean(flags[\"skip-install\"]),\n dev_port_explicit: flags[\"dev-port\"] !== undefined,\n preset: flags.preset ?? DEFAULT_SETUP_PRESET,\n use_case: flags[\"use-case\"] ?? DEFAULT_SETUP_USE_CASE,\n design: flags.design ?? \"built-in\",\n step: \"framework_resolved\",\n });\n\n // An explicit --dev-port overrides the detected port for the whole run, so\n // the issuer and the registered origin track the requested port (and several\n // apps can be scaffolded on distinct ports). The config edits set the\n // dev-server port only when it is unset, so a project that already pins a\n // different port in vite.config.*/angular.json keeps it — pass --dev-port to\n // match that pin (or remove it) if the origin check rejects requests.\n if (flags[\"dev-port\"] !== undefined) {\n const devPort = flags[\"dev-port\"];\n if (!Number.isInteger(devPort) || devPort < 1 || devPort > 65535) {\n throw new ZitadelError(\n \"E_VALIDATION\",\n `--dev-port must be an integer in 1..65535, got ${devPort}`,\n );\n }\n framework = {\n ...framework,\n devPort,\n url: issuerFromPort(devPort),\n };\n }\n\n let answers: SetupAnswers = {\n server: this.meta.source,\n devPort: framework.devPort,\n preset: (flags.preset as SetupPreset | undefined) ?? DEFAULT_SETUP_PRESET,\n useCase: (flags[\"use-case\"] as SetupUseCase | undefined) ?? DEFAULT_SETUP_USE_CASE,\n design: flags.design as BrandingDesign | undefined,\n };\n\n if (!nonInteractive && !dryRun) {\n intro(\"Zitadel setup\");\n const promptCtx = {\n framework,\n cwd,\n serverFlag: this.meta.serverFlag,\n devPortFromFlag: flags[\"dev-port\"] !== undefined,\n presetFromFlag: flags.preset !== undefined,\n useCaseFromFlag: flags[\"use-case\"] !== undefined,\n designFromFlag: flags.design !== undefined,\n };\n for (const prompt of SETUP_PROMPTS) {\n answers = await prompt.ask(answers, promptCtx);\n }\n outro(\"Configuration captured\");\n }\n\n // The interactive prompts can override the flag/default preset, use\n // case, and design recorded at framework_resolved — re-record so\n // telemetry carries the values that actually scaffold.\n this.recordTelemetry({\n preset: answers.preset,\n use_case: answers.useCase,\n design: answers.design ?? \"built-in\",\n });\n\n const issuer = issuerFromPort(answers.devPort);\n // The DevPortPrompt can change the port interactively, so fold the answer\n // back into the framework: the patched dev-server config reads\n // `framework.devPort`, and it must agree with the issuer and the registered\n // origin (both derived from `answers.devPort`).\n framework = { ...framework, devPort: answers.devPort, url: issuer };\n\n // `POST /projects` is unauthenticated. CLI-managed projects opt out of\n // server fallback defaults, then setup uploads the local default schema and\n // flow files through the typed resource APIs and records the returned IDs.\n consola.start(`Creating project on ${answers.server}${dryRun ? \" (dry run)\" : \"\"}`);\n const unauthClient = createZitadelClient({ baseUrl: answers.server });\n const projectName = defaultProjectName(cwd, framework.id);\n // Register the app's own origin so the backend's origin check allows\n // requests the dev proxy forwards from it.\n const project = dryRun\n ? dryRunProject(issuer)\n : await createProjectWithLocalHint(\n unauthClient,\n answers.server,\n this.meta.cliVersion,\n projectName,\n issuer,\n {\n // Resolved values, not raw flags: the wizard may have picked the\n // preset, design, or dev port interactively, and the retry must\n // reproduce those choices — the issuer registered with the\n // project derives from the port.\n ...retryOptionsFromFlags(flags),\n framework: framework.id,\n preset: answers.preset,\n useCase: answers.useCase,\n design: answers.design,\n devPort: answers.devPort,\n },\n );\n consola.success(`Created project ${project.id}`);\n this.recordTelemetry({ step: \"project_created\" });\n\n // Fresh scaffolds keep the widgets' full-page chrome; a pre-existing\n // route-based app gets embeddable cards inside its own layout (ADR 044).\n const posture = derivePosture(framework.id, scaffoldedFramework);\n const ctx: PatchContext = {\n framework,\n rendererId: flags.renderer ?? \"react\",\n project,\n issuer,\n server: answers.server,\n cliVersion: this.meta.cliVersion,\n scaffoldedFramework,\n posture,\n preset: answers.preset,\n useCase: answers.useCase,\n };\n consola.start(`Patching project files${dryRun ? \" (dry run)\" : \"\"}`);\n const result = await orca.patcherFor(framework.id).patch(ctx, { cwd, dryRun, force });\n for (const file of result.filesWritten) {\n const sentence = describeWrittenFile(relativeDisplay(cwd, file), dryRun);\n if (sentence) consola.info(sentence);\n }\n for (const file of result.filesSkipped) {\n consola.info(`Left ${relativeDisplay(cwd, file)} unchanged (already matches target)`);\n }\n let resourceResult: MaterializeSetupResourcesResult;\n try {\n resourceResult = dryRun\n ? { filesWritten: [] }\n : await materializeSetupResources({\n cwd,\n client: createZitadelClient({ baseUrl: answers.server, token: project.project_secret }),\n projectId: project.id,\n force,\n preset: answers.preset,\n useCase: answers.useCase,\n design: answers.design,\n cliVersion: this.meta.cliVersion,\n });\n } catch (error) {\n // Setup is not atomic: the patcher already wrote `zitadel.json` (the\n // marker the already-initialized guard skips on) and `.zitadel/secret`.\n // Remove both so a rerun starts a fresh setup instead of being skipped\n // forever with no default schema or login flow anywhere. The\n // half-provisioned project has no usable resources, so its credentials\n // are not worth keeping.\n await rm(join(cwd, \"zitadel.json\"), { force: true });\n await rm(join(cwd, \".zitadel/secret\"), { force: true });\n const cause = toZitadelError(error);\n throw new ZitadelError(cause.code, `Default resource setup failed: ${cause.message}`, {\n hint:\n \"The project was created but its default schema/flow upload did not finish. \" +\n \"Re-run `zitadel setup` to start over (add --force to overwrite partially \" +\n \"written .zitadel files).\",\n nextCommands: [\"zitadel setup --force\"],\n details: cause.details,\n });\n }\n for (const file of resourceResult.filesWritten) {\n const sentence = describeWrittenFile(relativeDisplay(cwd, file), dryRun);\n if (sentence) consola.info(sentence);\n }\n const allFilesWritten = [...result.filesWritten, ...resourceResult.filesWritten];\n consola.success(\n `Patched ${allFilesWritten.length} file${allFilesWritten.length === 1 ? \"\" : \"s\"}` +\n (result.filesSkipped.length > 0 ? ` (${result.filesSkipped.length} unchanged)` : \"\"),\n );\n this.recordTelemetry({\n step: \"files_patched\",\n files_written_count: allFilesWritten.length,\n });\n\n if (!dryRun) {\n // Record what was actually scaffolded so `doctor` can later verify the\n // app files without guessing from current templates (missing vs edited\n // vs user-adopted) and `doctor --fix` can restore exactly the missing\n // ones. Best-effort: a failure here only degrades doctor to its\n // template-derived fallback, it never breaks setup.\n try {\n await writeScaffoldManifest({\n cwd,\n actions: orca.patcherFor(framework.id).artifacts({\n framework,\n rendererId: ctx.rendererId,\n }),\n written: [...result.filesWritten, ...result.filesSkipped],\n scaffoldedFramework,\n devPort: answers.devPort,\n posture,\n });\n } catch (error) {\n consola.debug(\"Failed to record the scaffold manifest\", error);\n }\n }\n\n const installOutcome = await installDependenciesForSetup({\n cliVersion: this.meta.cliVersion,\n cwd,\n depsAdded: result.depsAdded,\n dryRun,\n env: this.meta.env,\n issuer,\n json: this.jsonEnabled(),\n scaffoldedFramework,\n skipInstall: Boolean(flags[\"skip-install\"]),\n });\n\n this.recordTelemetry({\n step: \"dependencies_installed\",\n package_manager: installOutcome.install.package_manager,\n });\n\n const writtenRel = allFilesWritten.map((file) => relativeDisplay(cwd, file));\n // The nudge rides both surfaces from one decision: the box for humans, the\n // envelope for agents.\n //\n // It joins `boxActions` rather than being held back from it. That list is\n // journey-staged by *omission* (customize/publish is absent until login\n // works, see `install.ts`), and this is not part of that journey: attaching\n // a team is orthogonal to whether login works yet, exactly as in `status`.\n // Position in the list carries no staging meaning, so appending is not a\n // way of deferring it.\n //\n // Empty off the cloud, where nothing can be attached.\n const claimNudge =\n claimState({ secret: {}, server: answers.server }).kind === \"detached\"\n ? {\n actions: [claimAction(this.meta.cliVersion)],\n commands: [claimCommand(this.meta.cliVersion)],\n }\n : { actions: [], commands: [] };\n // The structured report is human-only. Under `--json` we let the\n // envelope returned from `this.emit(...)` be the sole stdout\n // payload (oclif requires single-doc JSON).\n // The split-family brand pane collapses to the compact brand mark once the\n // login's container is narrow — and the template only emits that mark when\n // branding.json names an asset. Say so at setup time instead of letting the\n // branding's absence read as a rendering bug. Keyed to the design alone:\n // the collapse is a container query, so posture doesn't decide it (see\n // `designWarnings`).\n const warnings = designWarnings(answers.design);\n if (!this.jsonEnabled()) {\n const projectFacts = await detectProjectFacts(cwd, framework.id);\n const sections = buildSummary({\n projectFacts,\n writtenRel,\n project,\n server: answers.server,\n issuer,\n scaffoldedFramework,\n design: answers.design,\n });\n // Frame the report in a consola box so it reads as a distinct\n // status panel separate from the per-step narration above it.\n // `box` accepts ANSI-styled text in the message body, so our\n // pre-coloured rows (path/url/id helpers) survive intact.\n consola.box({\n title: \"Zitadel is ready\",\n message: [\n renderSummary(sections),\n \"\",\n [...installOutcome.boxActions, ...claimNudge.actions].join(\"\\n\"),\n ].join(\"\\n\"),\n style: { padding: 1, borderStyle: \"rounded\", borderColor: \"green\" },\n });\n // The envelope's `warnings` never render in non-JSON mode (setup\n // passes `pretty: \"\"`), so surface them to humans here.\n for (const warning of warnings) {\n consola.warn(warning);\n }\n }\n\n return this.emit({\n status: \"ok\",\n warnings,\n // Human-facing output was already shown via consola (box + per-step\n // narration). Pass an empty `pretty` so the base command's fallback\n // renderer doesn't duplicate the summary on stdout. The JSON envelope\n // still carries the full structured payload.\n pretty: \"\",\n data: {\n title: \"Zitadel is ready.\",\n project: { project_id: project.id, issuer },\n framework: framework.id,\n server: answers.server,\n files_written: allFilesWritten.map((file) => relativeDisplay(cwd, file)),\n // Typed per-artifact rows for the scaffolded app files (the sync\n // resources continue to report through files_written): one row per\n // touched path with kind (file/dir) and action (create/update), so\n // agents can verify what setup did without parsing narration.\n files: result.files.map((file) => ({\n path: relativeDisplay(cwd, file.path),\n kind: file.kind,\n action: file.action,\n })),\n files_skipped: result.filesSkipped.map((file) => relativeDisplay(cwd, file)),\n install: installOutcome.install,\n // The chosen login design, or null for the built-in template — so\n // agents can verify what setup published without diffing the repo.\n design: answers.design ?? null,\n // Branding guidance before the claim nudge: make it yours, then\n // claim to keep it (the same order the manifesto's journey walks).\n next_actions: [\n ...installOutcome.nextActions,\n brandingGuidanceAction(answers.design, this.meta.cliVersion),\n ...claimNudge.actions,\n ],\n next_commands: [...installOutcome.nextCommands, ...claimNudge.commands],\n },\n });\n }\n}\n\nfunction frameworkDetectionWithScaffoldTarget(\n error: ZitadelError,\n cwd: string,\n target: ScaffoldTarget,\n): ZitadelError {\n return new ZitadelError(\n error.code,\n \"Could not detect a supported app framework, and this directory is not a fresh scaffold target\",\n {\n hint:\n `${target.reason ?? \"Directory is not empty.\"} ` +\n \"Run setup from an empty directory to scaffold a new app, or run setup from an existing supported app project.\",\n details: { cwd, entries: target.entries, reason: target.reason },\n },\n );\n}\n\n/**\n * Resolves which framework to scaffold into an empty directory: the explicit\n * `--framework`, else PickFrameworkPrompt, else a hard error in non-interactive\n * mode (an agent must pass `--framework`).\n */\nasync function resolveScaffoldFramework(\n framework: string | undefined,\n nonInteractive: boolean,\n orca: Orca,\n): Promise<string> {\n if (framework) {\n return framework;\n }\n if (nonInteractive) {\n throw new ZitadelError(\"E_FRAMEWORK_NOT_DETECTED\", \"Empty directory — pass --framework\", {\n hint: \"Run without --json/--non-interactive to choose from a prompt, or pass --framework for scripted setup.\",\n });\n }\n return new PickFrameworkPrompt().ask(orca.availableFrameworks());\n}\n\n/** A deterministic stand-in project for `--dry-run`, so no remote call is made. */\nfunction dryRunProject(issuer: string): CreateProject201 {\n return {\n id: \"dry-run-0000\",\n project_secret: \"sk_proj_dry_run_full\",\n preview_secret: \"sk_proj_dry_run_preview\",\n preview_origins: [issuer],\n created_at: \"2026-04-21T14:03:11.000Z\",\n };\n}\n\n/**\n * The parts of a setup invocation that a retry suggestion must reproduce.\n * Suggested retries are followed verbatim (especially by agents), so dropping\n * a flag here silently changes what the retry scaffolds.\n */\ntype SetupRetryOptions = {\n framework?: string;\n preset?: SetupPreset;\n useCase?: SetupUseCase;\n design?: string;\n renderer?: string;\n devPort?: number;\n nonInteractive?: boolean;\n};\n\n/**\n * Reconstructs the flag list of the current invocation for retry guidance,\n * ending in `--server local`. Flags whose resolved value equals the default\n * are omitted — the retry reproduces the same outcome without them.\n */\nfunction setupRetryFlags(opts: SetupRetryOptions): string {\n const parts: string[] = [];\n if (opts.framework) {\n parts.push(`--framework ${opts.framework}`);\n }\n if (opts.preset && opts.preset !== DEFAULT_SETUP_PRESET) {\n parts.push(`--preset ${opts.preset}`);\n }\n if (opts.useCase && opts.useCase !== DEFAULT_SETUP_USE_CASE) {\n parts.push(`--use-case ${opts.useCase}`);\n }\n if (opts.design) {\n parts.push(`--design ${opts.design}`);\n }\n if (opts.renderer && opts.renderer !== \"react\") {\n parts.push(`--renderer ${opts.renderer}`);\n }\n if (opts.devPort !== undefined) {\n parts.push(`--dev-port ${opts.devPort}`);\n }\n if (opts.nonInteractive) {\n parts.push(\"--non-interactive\");\n }\n parts.push(\"--server local\");\n return parts.join(\" \");\n}\n\n/**\n * Retry options straight from parsed flags, for failures before the wizard\n * resolves answers. `--non-interactive` is echoed only when explicitly passed\n * — TTY/JSON-inferred non-interactivity re-infers itself on the retry.\n */\nfunction retryOptionsFromFlags(flags: {\n framework?: string;\n preset?: string;\n \"use-case\"?: string;\n design?: string;\n renderer?: string;\n \"dev-port\"?: number;\n \"non-interactive\"?: boolean;\n}): SetupRetryOptions {\n return {\n framework: flags.framework,\n preset: flags.preset as SetupPreset | undefined,\n useCase: flags[\"use-case\"] as SetupUseCase | undefined,\n design: flags.design,\n renderer: flags.renderer,\n devPort: flags[\"dev-port\"],\n nonInteractive: Boolean(flags[\"non-interactive\"]),\n };\n}\n\nasync function createProjectWithLocalHint(\n client: ReturnType<typeof createZitadelClient>,\n server: string,\n cliVersion: string,\n projectName: string,\n issuer: string,\n retry: SetupRetryOptions,\n): Promise<CreateProject201> {\n try {\n // API contract requires a project name; generated TS models may lag\n // briefly until `packages/api` regeneration catches up.\n const payload = { name: projectName, preview_origins: [issuer], seed_defaults: false } as {\n name: string;\n preview_origins: string[];\n seed_defaults: false;\n };\n // Register the app's own origin so the backend's origin check allows the\n // requests the dev proxy forwards from it.\n return await client.createProject(payload as Parameters<typeof client.createProject>[0]);\n } catch (error) {\n const normalized = toZitadelError(error);\n const retryFlags = setupRetryFlags(retry);\n throw new ZitadelError(normalized.code, normalized.message, {\n hint:\n `${normalized.hint ? `${normalized.hint} ` : \"\"}` +\n \"If you meant to use a local Zitadel server, start it first \" +\n `and retry setup with ${retryFlags}.`,\n nextCommands: [\n publicCliCommand(\"start\", cliVersion),\n publicCliCommand(`setup ${retryFlags}`, cliVersion),\n ],\n details: {\n server,\n original: normalized.details,\n },\n });\n }\n}\n\nfunction defaultProjectName(cwd: string, framework: string): string {\n const fromDirectory = basename(cwd).trim();\n return fromDirectory.length > 0 ? fromDirectory : `zitadel-${framework}-app`;\n}\n\nfunction localSetupHint(error: unknown, retry: SetupRetryOptions, cliVersion: string): unknown {\n const normalized = toZitadelError(error);\n if (normalized.code !== \"E_LOCAL_SERVER_NOT_RUNNING\") {\n return error;\n }\n\n const setupCommand = `setup ${setupRetryFlags(retry)}`;\n\n return new ZitadelError(normalized.code, normalized.message, {\n hint:\n `${normalized.hint ? `${normalized.hint} ` : \"\"}` +\n \"Start local Zitadel first, then rerun setup. \" +\n \"After setup succeeds, follow its next_commands to start the app and verify registration, logout, and login in the browser.\",\n nextCommands: [\n publicCliCommand(\"start\", cliVersion),\n publicCliCommand(setupCommand, cliVersion),\n ],\n details: normalized.details,\n });\n}\n\n/**\n * Replaces the user's `$HOME` with `~` in a path for compact terminal output.\n * Falls back to the raw path when `HOME` isn't set or doesn't match.\n */\nfunction shortPath(absolute: string): string {\n const home = process.env.HOME;\n if (home && absolute.startsWith(home)) {\n return `~${absolute.slice(home.length)}`;\n }\n return absolute;\n}\n\n/**\n * Picks one written file by suffix so the corresponding INSTALLED row can\n * reference it without hard-coding the path the patcher chose. Returns\n * the first match; falls back to `undefined` when the patcher didn't\n * write that artifact (e.g. a renderer without a register page).\n */\nfunction pickWrittenFile(written: string[], suffix: string): string | undefined {\n return written.find((file) => file.endsWith(suffix));\n}\n\n/**\n * Translates a patcher-written path into a single sentence the user can\n * read at narration speed. The patch result's `filesWritten` carries\n * deduplicated file paths only (directories stay in the typed `files`\n * rows), so no artefact filtering is needed here. The verb tense flips\n * for `--dry-run` so the user sees a preview (\"Would write ...\") instead\n * of a claim that something happened.\n */\nfunction describeWrittenFile(relPath: string, dryRun: boolean): string | null {\n const verb = dryRun ? \"Would write\" : \"Wrote\";\n const sentence = SENTENCE_BY_PATH[relPath];\n if (sentence) {\n return `${verb} ${sentence.subject} (${stylePath(relPath)})`;\n }\n return `${verb} ${stylePath(relPath)}`;\n}\n\n/**\n * Map from the patcher's deterministic output paths to a short noun\n * phrase describing what the file is for. Anything not in the map falls\n * back to the bare path in the narration; add an entry here when a new\n * scaffolded file deserves a clearer label.\n */\nconst SENTENCE_BY_PATH: Record<string, { subject: string }> = {\n \".gitignore\": { subject: \"the project's .gitignore additions\" },\n \".zitadel/secret\": { subject: \"the local project secret\" },\n \"zitadel.json\": { subject: \"the Zitadel project configuration\" },\n \".env.example\": { subject: \"the .env example template\" },\n \".env.local\": { subject: \"the local development environment variables\" },\n \".zitadel/state.json\": { subject: \"the sync state file\" },\n \".zitadel/flows/default-login.json\": { subject: \"the editable default login flow\" },\n \".zitadel/flows/README.md\": { subject: \"the flows folder README\" },\n \".zitadel/schemas/default-human-user.json\": {\n subject: \"the editable default human user schema\",\n },\n \".zitadel/schemas/README.md\": { subject: \"the schemas folder README\" },\n \".zitadel/meta/flow-definition.json\": { subject: \"the flow dialect spec (editor $schema)\" },\n \".zitadel/meta/user-schema.json\": { subject: \"the user-schema dialect spec\" },\n \".zitadel/meta/user-property.json\": { subject: \"the user-property dialect spec\" },\n \".zitadel/meta/branding.json\": { subject: \"the branding dialect spec\" },\n \".zitadel/branding/branding.json\": { subject: \"the branding descriptor (layout + asset URLs)\" },\n \".zitadel/branding/login.liquid\": { subject: \"the editable login template\" },\n \".zitadel/branding/README.md\": { subject: \"the branding folder README\" },\n \"AGENTS.md\": { subject: \"the agent guidance (golden journey + config dialect)\" },\n \"README.md\": { subject: \"the README's Zitadel section\" },\n \"app/page.tsx\": { subject: \"the home page redirect\" },\n \"app/login/page.tsx\": { subject: \"the login page\" },\n \"app/register/page.tsx\": { subject: \"the registration page\" },\n \"app/profile/page.tsx\": { subject: \"the profile page\" },\n \"middleware.ts\": { subject: \"the Next.js middleware\" },\n \"proxy.ts\": { subject: \"the Next.js proxy\" },\n \"custom-elements.d.ts\": { subject: \"the web-component type declarations\" },\n \"package.json\": { subject: \"package.json with the SDK dependency\" },\n};\n\n/** Builds the section list driving {@link renderSummary} for the setup command. */\nfunction buildSummary(opts: {\n projectFacts: Awaited<ReturnType<typeof detectProjectFacts>>;\n writtenRel: string[];\n project: CreateProject201;\n server: string;\n issuer: string;\n scaffoldedFramework: boolean;\n design?: BrandingDesign;\n}): Section[] {\n const { projectFacts, writtenRel, project, server, issuer, scaffoldedFramework, design } = opts;\n const sdkPackage = \"@zitadel/sdk-next\";\n const packageJsonHit = pickWrittenFile(writtenRel, \"package.json\");\n\n const detected: Row[] = [{ label: \"Framework\", value: formatFrameworkLine(projectFacts) }];\n if (scaffoldedFramework) {\n detected.push({ label: \"Scaffold\", value: \"fresh project (no existing files)\" });\n }\n\n const installedRows: Row[] = [];\n if (packageJsonHit) {\n installedRows.push({\n label: \"Package\",\n value: sdkPackage,\n secondary: stylePath(fileNameOf(packageJsonHit)),\n });\n }\n for (const [label, suffix] of [\n [\"Home redirect\", \"app/page.tsx\"],\n [\"Login page\", \"app/login/page.tsx\"],\n [\"Register page\", \"app/register/page.tsx\"],\n [\"Profile page\", \"app/profile/page.tsx\"],\n [\"Request proxy\", \"proxy.ts\"],\n [\"Middleware\", \"middleware.ts\"],\n [\"Env vars\", \".env.local\"],\n ] as const) {\n const hit = pickWrittenFile(writtenRel, suffix);\n if (hit) installedRows.push({ label, value: stylePath(hit) });\n }\n\n // The login-customization entry points. These are what a user edits to\n // change what the login collects, how it authenticates, and how it looks —\n // burying them in the verbose per-file narration above the box means users\n // don't find them (each folder ships a README with the workflow).\n const customizeRows: Row[] = [];\n for (const [label, suffix, dir] of [\n [\"User schema\", \".zitadel/schemas/default-human-user.json\", \".zitadel/schemas/\"],\n [\"Login flow\", \".zitadel/flows/default-login.json\", \".zitadel/flows/\"],\n [\"Login template\", \".zitadel/branding/login.liquid\", \".zitadel/branding/\"],\n ] as const) {\n const hit = pickWrittenFile(writtenRel, suffix);\n if (hit) customizeRows.push({ label, value: stylePath(dir), secondary: \"see its README.md\" });\n }\n\n const projectRows: Row[] = [\n { label: \"Project id\", value: styleId(project.id) },\n { label: \"Server\", value: styleUrl(server) },\n { label: \"App will run\", value: styleUrl(issuer) },\n design\n ? {\n label: \"Login design\",\n value: brandingDesignLabel(design),\n secondary: `${design} · ${stylePath(\".zitadel/branding/\")}`,\n }\n : { label: \"Login design\", value: styleDim(\"built-in template\") },\n ];\n\n return [\n { title: \"Detected\", rows: detected },\n { title: \"Installed\", rows: installedRows },\n { title: \"Customize\", rows: customizeRows },\n { title: \"Project\", rows: projectRows },\n ];\n}\n"],"mappings":"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"}
|
package/dist/commands/start.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { D as
|
|
2
|
-
import { c as metadataFromStart, f as binaryLogs, g as stopBinaryRuntime, h as startBinaryRuntime, i as ensureImage, l as startContainer, m as isProcessRunning, n as currentUser, r as dockerAvailable, s as inspectContainer, u as stopAndRemoveContainer } from "../docker-
|
|
3
|
-
import { n as dockerRuntimeGuidance, r as dockerUnavailableMessage, t as listenersForPort } from "../ports-
|
|
1
|
+
import { D as toZitadelError, E as ZitadelError, a as DEFAULT_LOCAL_SERVER_PORT, c as checkLocalServerHealth, d as ensureContainerIdentity, f as ensureLocalState, h as readRuntimeMetadata, j as publicCliCommand, l as defaultLocalServerImageForCliVersion, m as localServerUrl, p as localContainerName, t as BaseCommand, y as writeRuntimeMetadata } from "../oclif-CanO3zdt.mjs";
|
|
2
|
+
import { c as metadataFromStart, f as binaryLogs, g as stopBinaryRuntime, h as startBinaryRuntime, i as ensureImage, l as startContainer, m as isProcessRunning, n as currentUser, r as dockerAvailable, s as inspectContainer, u as stopAndRemoveContainer } from "../docker-DcRGTOJa.mjs";
|
|
3
|
+
import { n as dockerRuntimeGuidance, r as dockerUnavailableMessage, t as listenersForPort } from "../ports-BM20XIZb.mjs";
|
|
4
4
|
import { Flags } from "@oclif/core";
|
|
5
5
|
import { setTimeout } from "node:timers/promises";
|
|
6
6
|
//#region src/commands/start.ts
|
package/dist/commands/status.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { n as
|
|
4
|
-
import {
|
|
1
|
+
import { c as checkLocalServerHealth, h as readRuntimeMetadata, j as publicCliCommand, t as BaseCommand, v as runtimeSummary, x as resolveCwd } from "../oclif-CanO3zdt.mjs";
|
|
2
|
+
import { n as claimCommand, r as claimState, t as claimAction } from "../claim-state-DlfD6Res.mjs";
|
|
3
|
+
import { n as customizeAndPublishActions, r as verifyLoginAction } from "../journey-guidance-BGrOX_gT.mjs";
|
|
4
|
+
import { a as readProjectServer, c as readZitadelConfig, l as readZitadelSecret, n as hasZitadelSecret, r as readDevelopmentIssuer, t as hasZitadelConfig } from "../project-CHhot85s.mjs";
|
|
5
|
+
import { m as isProcessRunning, s as inspectContainer } from "../docker-DcRGTOJa.mjs";
|
|
5
6
|
import { createZitadelClient } from "@zitadel/api/client";
|
|
6
7
|
//#region src/commands/status.ts
|
|
7
8
|
/**
|
|
@@ -38,7 +39,7 @@ var Status = class Status extends BaseCommand {
|
|
|
38
39
|
});
|
|
39
40
|
const project = await projectStatus(this.meta.cwd);
|
|
40
41
|
const users = project.lifecycle === "configured" ? await detectUserPresence(this.meta.cwd, this.meta.source) : "unknown";
|
|
41
|
-
const nextCommands = nextCommandsFor(serverLifecycle, project
|
|
42
|
+
const nextCommands = nextCommandsFor(serverLifecycle, project, users, this.meta.cliVersion);
|
|
42
43
|
const nextActions = nextActionsFor(project, users, this.meta.cliVersion);
|
|
43
44
|
return this.emit({
|
|
44
45
|
status: "ok",
|
|
@@ -91,10 +92,15 @@ async function projectStatus(cwd) {
|
|
|
91
92
|
message: "zitadel.json exists but .zitadel/secret is missing."
|
|
92
93
|
};
|
|
93
94
|
const secret = await readZitadelSecret(cwd);
|
|
95
|
+
const claim = claimState({
|
|
96
|
+
secret,
|
|
97
|
+
server: readProjectServer(config)
|
|
98
|
+
});
|
|
94
99
|
return {
|
|
95
100
|
lifecycle: "configured",
|
|
96
101
|
project_id: String(config.project ?? secret.project_id ?? ""),
|
|
97
|
-
issuer: readDevelopmentIssuer(config)
|
|
102
|
+
issuer: readDevelopmentIssuer(config),
|
|
103
|
+
...claim.kind === "not-applicable" ? {} : { claim }
|
|
98
104
|
};
|
|
99
105
|
}
|
|
100
106
|
const PRESENCE_PROBE_TIMEOUT_MS = 1500;
|
|
@@ -110,7 +116,7 @@ async function detectUserPresence(cwd, source) {
|
|
|
110
116
|
const probe = createZitadelClient({
|
|
111
117
|
baseUrl: source,
|
|
112
118
|
token: (await readZitadelSecret(cwd)).project_secret
|
|
113
|
-
}).listUsers({ limit: 1 }, { signal: AbortSignal.timeout(PRESENCE_PROBE_TIMEOUT_MS) }).then((users) => users.length > 0 ? "some" : "none").catch(() => "unknown");
|
|
119
|
+
}).listUsers({ limit: 1 }, { signal: AbortSignal.timeout(PRESENCE_PROBE_TIMEOUT_MS) }).then(({ users }) => users.length > 0 ? "some" : "none").catch(() => "unknown");
|
|
114
120
|
return await Promise.race([probe, new Promise((resolve) => {
|
|
115
121
|
setTimeout(() => resolve("unknown"), PRESENCE_PROBE_TIMEOUT_MS + 250).unref();
|
|
116
122
|
})]);
|
|
@@ -121,17 +127,19 @@ async function detectUserPresence(cwd, source) {
|
|
|
121
127
|
function nextActionsFor(project, users, cliVersion) {
|
|
122
128
|
if (project.lifecycle === "not-configured") return ["From your app directory, run setup; the CLI will detect the framework or ask in an empty directory."];
|
|
123
129
|
if (project.lifecycle !== "configured") return [];
|
|
124
|
-
|
|
125
|
-
if (users === "
|
|
126
|
-
return [];
|
|
130
|
+
const claim = project.claim?.kind === "detached" ? [claimAction(cliVersion)] : [];
|
|
131
|
+
if (users === "none") return [verifyLoginAction(project.issuer), ...claim];
|
|
132
|
+
if (users === "some") return [...customizeAndPublishActions(cliVersion), ...claim];
|
|
133
|
+
return claim;
|
|
127
134
|
}
|
|
128
|
-
function nextCommandsFor(serverLifecycle,
|
|
135
|
+
function nextCommandsFor(serverLifecycle, project, users, cliVersion) {
|
|
129
136
|
const commands = [];
|
|
130
137
|
if (serverLifecycle !== "running") commands.push(publicCliCommand("start", cliVersion));
|
|
131
|
-
if (
|
|
132
|
-
else if (
|
|
138
|
+
if (project.lifecycle === "not-configured") commands.push(publicCliCommand("setup --server local", cliVersion));
|
|
139
|
+
else if (project.lifecycle === "orphaned-config") commands.push(publicCliCommand("setup --force", cliVersion), publicCliCommand("doctor --fix", cliVersion));
|
|
133
140
|
else {
|
|
134
141
|
commands.push(publicCliCommand("doctor", cliVersion));
|
|
142
|
+
if (project.claim?.kind === "detached") commands.push(claimCommand(cliVersion));
|
|
135
143
|
if (users === "none") commands.push(publicCliCommand("plan", cliVersion));
|
|
136
144
|
else commands.push(publicCliCommand("apply", cliVersion));
|
|
137
145
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.mjs","names":[],"sources":["../../src/commands/status.ts"],"sourcesContent":["import { createZitadelClient } from \"@zitadel/api/client\";\n\nimport { isProcessRunning } from \"../lib/local-server/binary\";\nimport { inspectContainer } from \"../lib/local-server/docker\";\nimport { customizeAndPublishActions, verifyLoginAction } from \"../lib/journey-guidance\";\nimport {\n DEFAULT_LOCAL_SERVER_URL,\n checkLocalServerHealth,\n readRuntimeMetadata,\n runtimeSummary,\n} from \"../lib/local-server/runtime\";\nimport { BaseCommand, type JsonEnvelope } from \"../lib/oclif\";\nimport { resolveCwd } from \"../lib/paths\";\nimport {\n hasZitadelConfig,\n hasZitadelSecret,\n readDevelopmentIssuer,\n readZitadelConfig,\n readZitadelSecret,\n} from \"../lib/project\";\nimport { publicCliCommand } from \"../lib/public-cli\";\n\n/**\n * `zitadel status` — summarize the local server and project state.\n *\n * This is intentionally informational: a missing `zitadel.json`, stopped\n * local server, or orphaned config should be visible without making `status`\n * itself fail.\n */\nexport default class Status extends BaseCommand {\n static override description = \"Summarize the local Zitadel server and project state.\";\n\n async run(): Promise<JsonEnvelope> {\n const { flags } = await this.parse(Status);\n const cwd = resolveCwd(typeof flags.cwd === \"string\" ? flags.cwd : undefined);\n const runtime = await readRuntimeMetadata(cwd);\n if (flags.server === \"local\") {\n await this.toMeta(flags, {\n resolveServer: false,\n source: runtime?.server_url ?? DEFAULT_LOCAL_SERVER_URL,\n });\n } else {\n await this.toMeta(flags);\n }\n let docker: Awaited<ReturnType<typeof inspectContainer>> | undefined;\n let dockerError: string | undefined;\n if (runtime?.backend === \"docker\") {\n try {\n docker = await inspectContainer(runtime.container_name);\n } catch (error) {\n dockerError = error instanceof Error ? error.message : String(error);\n }\n }\n const healthy = runtime ? await checkLocalServerHealth(runtime.server_url) : false;\n const processRunning = runtime?.backend === \"binary\" ? isProcessRunning(runtime.pid) : false;\n const serverLifecycle = lifecycleForRuntime({ docker, healthy, processRunning, runtime });\n\n const project = await projectStatus(this.meta.cwd);\n const users =\n project.lifecycle === \"configured\"\n ? await detectUserPresence(this.meta.cwd, this.meta.source)\n : \"unknown\";\n const nextCommands = nextCommandsFor(\n serverLifecycle,\n project.lifecycle,\n users,\n this.meta.cliVersion,\n );\n const nextActions = nextActionsFor(project, users, this.meta.cliVersion);\n\n return this.emit({\n status: \"ok\",\n data: {\n title: \"Zitadel status.\",\n server: {\n lifecycle: serverLifecycle,\n runtime: runtimeSummary(runtime),\n docker: {\n available: dockerError === undefined,\n error: dockerError,\n container_exists: docker?.exists ?? false,\n container_running: docker?.running ?? false,\n },\n process:\n runtime?.backend === \"binary\"\n ? {\n pid: runtime.pid,\n running: processRunning,\n }\n : undefined,\n health: {\n healthy,\n url: runtime?.server_url,\n },\n },\n project,\n next_actions: nextActions,\n next_commands: nextCommands,\n },\n });\n }\n}\n\nfunction lifecycleForRuntime(input: {\n docker: Awaited<ReturnType<typeof inspectContainer>> | undefined;\n healthy: boolean;\n processRunning: boolean;\n runtime: Awaited<ReturnType<typeof readRuntimeMetadata>>;\n}): string {\n if (!input.runtime) {\n return \"missing\";\n }\n if (input.runtime.backend === \"binary\") {\n if (input.processRunning && input.healthy) {\n return \"running\";\n }\n return input.processRunning ? \"unhealthy\" : \"stopped\";\n }\n if (input.docker?.running && input.healthy) {\n return \"running\";\n }\n if (input.docker?.exists) {\n return \"unhealthy\";\n }\n return \"stopped\";\n}\n\ntype ProjectStatus =\n | {\n lifecycle: \"not-configured\";\n message: string;\n }\n | {\n lifecycle: \"orphaned-config\";\n project_id?: string;\n message: string;\n }\n | {\n lifecycle: \"configured\";\n project_id: string;\n issuer?: string;\n };\n\nasync function projectStatus(cwd: string): Promise<ProjectStatus> {\n if (!(await hasZitadelConfig(cwd))) {\n return {\n lifecycle: \"not-configured\",\n message: \"zitadel.json has not been created yet.\",\n };\n }\n\n const config = await readZitadelConfig(cwd);\n if (!(await hasZitadelSecret(cwd))) {\n return {\n lifecycle: \"orphaned-config\",\n project_id: typeof config.project === \"string\" ? config.project : undefined,\n message: \"zitadel.json exists but .zitadel/secret is missing.\",\n };\n }\n\n const secret = await readZitadelSecret(cwd);\n return {\n lifecycle: \"configured\",\n project_id: String(config.project ?? secret.project_id ?? \"\"),\n issuer: readDevelopmentIssuer(config),\n };\n}\n\ntype UserPresence = \"none\" | \"some\" | \"unknown\";\n\nconst PRESENCE_PROBE_TIMEOUT_MS = 1500;\n\n/**\n * Whether the project has any users yet — the journey signal that stages the\n * guidance: before the first successful registration the next step is\n * verifying login, afterwards it is customizing and publishing config. Best\n * effort by design: any failure (server unreachable, stale secret, timeout)\n * reads as `unknown` and the caller keeps the lifecycle-only output.\n */\nasync function detectUserPresence(cwd: string, source: string): Promise<UserPresence> {\n try {\n const secret = await readZitadelSecret(cwd);\n const client = createZitadelClient({\n baseUrl: source,\n token: secret.project_secret,\n });\n const probe = client\n .listUsers({ limit: 1 }, { signal: AbortSignal.timeout(PRESENCE_PROBE_TIMEOUT_MS) })\n .then((users): UserPresence => (users.length > 0 ? \"some\" : \"none\"))\n .catch((): UserPresence => \"unknown\");\n // The abort signal alone is not enough: DNS resolution can outlive it\n // (getaddrinfo runs on the threadpool and some environments take many\n // seconds to fail), and `status` must stay snappy. Race a detached timer\n // so the answer degrades to \"unknown\" at the deadline no matter what the\n // socket layer does; unref'd so it never keeps the CLI process alive.\n return await Promise.race([\n probe,\n new Promise<UserPresence>((resolve) => {\n setTimeout(() => resolve(\"unknown\"), PRESENCE_PROBE_TIMEOUT_MS + 250).unref();\n }),\n ]);\n } catch {\n return \"unknown\";\n }\n}\n\nfunction nextActionsFor(project: ProjectStatus, users: UserPresence, cliVersion: string): string[] {\n if (project.lifecycle === \"not-configured\") {\n return [\n \"From your app directory, run setup; the CLI will detect the framework or ask in an empty directory.\",\n ];\n }\n if (project.lifecycle !== \"configured\") {\n return [];\n }\n if (users === \"none\") {\n return [verifyLoginAction(project.issuer)];\n }\n if (users === \"some\") {\n return customizeAndPublishActions(cliVersion);\n }\n return [];\n}\n\nfunction nextCommandsFor(\n serverLifecycle: string,\n projectLifecycle: ProjectStatus[\"lifecycle\"],\n users: UserPresence,\n cliVersion: string,\n): string[] {\n const commands: string[] = [];\n if (serverLifecycle !== \"running\") {\n commands.push(publicCliCommand(\"start\", cliVersion));\n }\n if (projectLifecycle === \"not-configured\") {\n commands.push(publicCliCommand(\"setup --server local\", cliVersion));\n } else if (projectLifecycle === \"orphaned-config\") {\n commands.push(\n publicCliCommand(\"setup --force\", cliVersion),\n publicCliCommand(\"doctor --fix\", cliVersion),\n );\n } else {\n commands.push(publicCliCommand(\"doctor\", cliVersion));\n if (users === \"none\") {\n // Staged like next_actions: before the first login is proven in a\n // browser, publishing is premature — `plan` previews safely and the\n // verify mission lives in next_actions. `apply` joins once users\n // exist (\"some\") or when the probe can't tell (\"unknown\" keeps the\n // lifecycle-only behavior rather than withholding on no signal).\n commands.push(publicCliCommand(\"plan\", cliVersion));\n } else {\n commands.push(publicCliCommand(\"apply\", cliVersion));\n }\n }\n return commands;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"status.mjs","names":[],"sources":["../../src/commands/status.ts"],"sourcesContent":["import { createZitadelClient } from \"@zitadel/api/client\";\n\nimport { claimAction, claimCommand, claimState, type ClaimState } from \"../lib/claim-state\";\nimport { isProcessRunning } from \"../lib/local-server/binary\";\nimport { inspectContainer } from \"../lib/local-server/docker\";\nimport { customizeAndPublishActions, verifyLoginAction } from \"../lib/journey-guidance\";\nimport {\n DEFAULT_LOCAL_SERVER_URL,\n checkLocalServerHealth,\n readRuntimeMetadata,\n runtimeSummary,\n} from \"../lib/local-server/runtime\";\nimport { BaseCommand, type JsonEnvelope } from \"../lib/oclif\";\nimport { resolveCwd } from \"../lib/paths\";\nimport {\n hasZitadelConfig,\n hasZitadelSecret,\n readDevelopmentIssuer,\n readProjectServer,\n readZitadelConfig,\n readZitadelSecret,\n} from \"../lib/project\";\nimport { publicCliCommand } from \"../lib/public-cli\";\n\n/**\n * `zitadel status` — summarize the local server and project state.\n *\n * This is intentionally informational: a missing `zitadel.json`, stopped\n * local server, or orphaned config should be visible without making `status`\n * itself fail.\n */\nexport default class Status extends BaseCommand {\n static override description = \"Summarize the local Zitadel server and project state.\";\n\n async run(): Promise<JsonEnvelope> {\n const { flags } = await this.parse(Status);\n const cwd = resolveCwd(typeof flags.cwd === \"string\" ? flags.cwd : undefined);\n const runtime = await readRuntimeMetadata(cwd);\n if (flags.server === \"local\") {\n await this.toMeta(flags, {\n resolveServer: false,\n source: runtime?.server_url ?? DEFAULT_LOCAL_SERVER_URL,\n });\n } else {\n await this.toMeta(flags);\n }\n let docker: Awaited<ReturnType<typeof inspectContainer>> | undefined;\n let dockerError: string | undefined;\n if (runtime?.backend === \"docker\") {\n try {\n docker = await inspectContainer(runtime.container_name);\n } catch (error) {\n dockerError = error instanceof Error ? error.message : String(error);\n }\n }\n const healthy = runtime ? await checkLocalServerHealth(runtime.server_url) : false;\n const processRunning = runtime?.backend === \"binary\" ? isProcessRunning(runtime.pid) : false;\n const serverLifecycle = lifecycleForRuntime({ docker, healthy, processRunning, runtime });\n\n const project = await projectStatus(this.meta.cwd);\n const users =\n project.lifecycle === \"configured\"\n ? await detectUserPresence(this.meta.cwd, this.meta.source)\n : \"unknown\";\n const nextCommands = nextCommandsFor(serverLifecycle, project, users, this.meta.cliVersion);\n const nextActions = nextActionsFor(project, users, this.meta.cliVersion);\n\n return this.emit({\n status: \"ok\",\n data: {\n title: \"Zitadel status.\",\n server: {\n lifecycle: serverLifecycle,\n runtime: runtimeSummary(runtime),\n docker: {\n available: dockerError === undefined,\n error: dockerError,\n container_exists: docker?.exists ?? false,\n container_running: docker?.running ?? false,\n },\n process:\n runtime?.backend === \"binary\"\n ? {\n pid: runtime.pid,\n running: processRunning,\n }\n : undefined,\n health: {\n healthy,\n url: runtime?.server_url,\n },\n },\n project,\n next_actions: nextActions,\n next_commands: nextCommands,\n },\n });\n }\n}\n\nfunction lifecycleForRuntime(input: {\n docker: Awaited<ReturnType<typeof inspectContainer>> | undefined;\n healthy: boolean;\n processRunning: boolean;\n runtime: Awaited<ReturnType<typeof readRuntimeMetadata>>;\n}): string {\n if (!input.runtime) {\n return \"missing\";\n }\n if (input.runtime.backend === \"binary\") {\n if (input.processRunning && input.healthy) {\n return \"running\";\n }\n return input.processRunning ? \"unhealthy\" : \"stopped\";\n }\n if (input.docker?.running && input.healthy) {\n return \"running\";\n }\n if (input.docker?.exists) {\n return \"unhealthy\";\n }\n return \"stopped\";\n}\n\ntype ProjectStatus =\n | {\n lifecycle: \"not-configured\";\n message: string;\n }\n | {\n lifecycle: \"orphaned-config\";\n project_id?: string;\n message: string;\n }\n | {\n lifecycle: \"configured\";\n project_id: string;\n issuer?: string;\n /**\n * Whether the project is attached to a team, from the local\n * `.zitadel/secret`. Omitted entirely off the cloud, where there is\n * nothing to attach and the field would only invite agents to act on it.\n */\n claim?: ClaimState;\n };\n\nasync function projectStatus(cwd: string): Promise<ProjectStatus> {\n if (!(await hasZitadelConfig(cwd))) {\n return {\n lifecycle: \"not-configured\",\n message: \"zitadel.json has not been created yet.\",\n };\n }\n\n const config = await readZitadelConfig(cwd);\n if (!(await hasZitadelSecret(cwd))) {\n return {\n lifecycle: \"orphaned-config\",\n project_id: typeof config.project === \"string\" ? config.project : undefined,\n message: \"zitadel.json exists but .zitadel/secret is missing.\",\n };\n }\n\n const secret = await readZitadelSecret(cwd);\n // Gated on the server recorded in `zitadel.json`, not `this.meta.source`:\n // `status --server local` rewrites the source for the health probe, but it\n // does not move the project, so the source would answer the wrong question.\n const claim = claimState({ secret, server: readProjectServer(config) });\n return {\n lifecycle: \"configured\",\n project_id: String(config.project ?? secret.project_id ?? \"\"),\n issuer: readDevelopmentIssuer(config),\n ...(claim.kind === \"not-applicable\" ? {} : { claim }),\n };\n}\n\ntype UserPresence = \"none\" | \"some\" | \"unknown\";\n\nconst PRESENCE_PROBE_TIMEOUT_MS = 1500;\n\n/**\n * Whether the project has any users yet — the journey signal that stages the\n * guidance: before the first successful registration the next step is\n * verifying login, afterwards it is customizing and publishing config. Best\n * effort by design: any failure (server unreachable, stale secret, timeout)\n * reads as `unknown` and the caller keeps the lifecycle-only output.\n */\nasync function detectUserPresence(cwd: string, source: string): Promise<UserPresence> {\n try {\n const secret = await readZitadelSecret(cwd);\n const client = createZitadelClient({\n baseUrl: source,\n token: secret.project_secret,\n });\n const probe = client\n .listUsers({ limit: 1 }, { signal: AbortSignal.timeout(PRESENCE_PROBE_TIMEOUT_MS) })\n .then(({ users }): UserPresence => (users.length > 0 ? \"some\" : \"none\"))\n .catch((): UserPresence => \"unknown\");\n // The abort signal alone is not enough: DNS resolution can outlive it\n // (getaddrinfo runs on the threadpool and some environments take many\n // seconds to fail), and `status` must stay snappy. Race a detached timer\n // so the answer degrades to \"unknown\" at the deadline no matter what the\n // socket layer does; unref'd so it never keeps the CLI process alive.\n return await Promise.race([\n probe,\n new Promise<UserPresence>((resolve) => {\n setTimeout(() => resolve(\"unknown\"), PRESENCE_PROBE_TIMEOUT_MS + 250).unref();\n }),\n ]);\n } catch {\n return \"unknown\";\n }\n}\n\nfunction nextActionsFor(project: ProjectStatus, users: UserPresence, cliVersion: string): string[] {\n if (project.lifecycle === \"not-configured\") {\n return [\n \"From your app directory, run setup; the CLI will detect the framework or ask in an empty directory.\",\n ];\n }\n if (project.lifecycle !== \"configured\") {\n return [];\n }\n // Additive to the journey staging rather than a stage of its own: attaching a\n // team is orthogonal to whether login works yet, so it appends to whichever\n // stage the user is in instead of displacing it.\n const claim = project.claim?.kind === \"detached\" ? [claimAction(cliVersion)] : [];\n if (users === \"none\") {\n return [verifyLoginAction(project.issuer), ...claim];\n }\n if (users === \"some\") {\n return [...customizeAndPublishActions(cliVersion), ...claim];\n }\n return claim;\n}\n\nfunction nextCommandsFor(\n serverLifecycle: string,\n project: ProjectStatus,\n users: UserPresence,\n cliVersion: string,\n): string[] {\n const commands: string[] = [];\n if (serverLifecycle !== \"running\") {\n commands.push(publicCliCommand(\"start\", cliVersion));\n }\n if (project.lifecycle === \"not-configured\") {\n commands.push(publicCliCommand(\"setup --server local\", cliVersion));\n } else if (project.lifecycle === \"orphaned-config\") {\n commands.push(\n publicCliCommand(\"setup --force\", cliVersion),\n publicCliCommand(\"doctor --fix\", cliVersion),\n );\n } else {\n commands.push(publicCliCommand(\"doctor\", cliVersion));\n if (project.claim?.kind === \"detached\") {\n commands.push(claimCommand(cliVersion));\n }\n if (users === \"none\") {\n // Staged like next_actions: before the first login is proven in a\n // browser, publishing is premature — `plan` previews safely and the\n // verify mission lives in next_actions. `apply` joins once users\n // exist (\"some\") or when the probe can't tell (\"unknown\" keeps the\n // lifecycle-only behavior rather than withholding on no signal).\n commands.push(publicCliCommand(\"plan\", cliVersion));\n } else {\n commands.push(publicCliCommand(\"apply\", cliVersion));\n }\n }\n return commands;\n}\n"],"mappings":"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"}
|