@zitadel/cli 0.1.0-alpha.13 → 0.1.0-alpha.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +137 -57
  2. package/SKILLS.md +26 -13
  3. package/dist/commands/apply.mjs +6 -4
  4. package/dist/commands/apply.mjs.map +1 -1
  5. package/dist/commands/doctor.mjs +89 -12
  6. package/dist/commands/doctor.mjs.map +1 -1
  7. package/dist/commands/eject.mjs +4 -4
  8. package/dist/commands/logs.mjs +2 -2
  9. package/dist/commands/plan.mjs +6 -4
  10. package/dist/commands/plan.mjs.map +1 -1
  11. package/dist/commands/reset.mjs +2 -2
  12. package/dist/commands/schemas/list.mjs +134 -0
  13. package/dist/commands/schemas/list.mjs.map +1 -0
  14. package/dist/commands/setup.mjs +130 -15
  15. package/dist/commands/setup.mjs.map +1 -1
  16. package/dist/commands/start.mjs +4 -4
  17. package/dist/commands/status.mjs +3 -3
  18. package/dist/commands/stop.mjs +3 -3
  19. package/dist/{docker-Djz6BLp9.mjs → docker-D7BSD5C9.mjs} +3 -3
  20. package/dist/{docker-Djz6BLp9.mjs.map → docker-D7BSD5C9.mjs.map} +1 -1
  21. package/dist/{docker-guidance-D-33g1uV.mjs → docker-guidance-mcTT3_0E.mjs} +2 -2
  22. package/dist/{docker-guidance-D-33g1uV.mjs.map → docker-guidance-mcTT3_0E.mjs.map} +1 -1
  23. package/dist/environment-BQF7LeCz.mjs +17 -0
  24. package/dist/environment-BQF7LeCz.mjs.map +1 -0
  25. package/dist/{oclif-BoUVygsZ.mjs → oclif-Bm-FkF6z.mjs} +66 -13
  26. package/dist/oclif-Bm-FkF6z.mjs.map +1 -0
  27. package/dist/{orca-DU8myWGm.mjs → orca-CpXj_XsA.mjs} +46 -94
  28. package/dist/orca-CpXj_XsA.mjs.map +1 -0
  29. package/dist/{ports-B09RjuHx.mjs → ports-CxBKS1ga.mjs} +1 -1
  30. package/dist/{ports-B09RjuHx.mjs.map → ports-CxBKS1ga.mjs.map} +1 -1
  31. package/dist/{processes-Cw8TO1SY.mjs → processes-BVqYsxT8.mjs} +1 -1
  32. package/dist/{processes-Cw8TO1SY.mjs.map → processes-BVqYsxT8.mjs.map} +1 -1
  33. package/dist/{project-B1qVQMKS.mjs → project-Dk7V0xka.mjs} +3 -3
  34. package/dist/{project-B1qVQMKS.mjs.map → project-Dk7V0xka.mjs.map} +1 -1
  35. package/dist/{sync-B8Z2it_E.mjs → sync-nSLnVhKK.mjs} +123 -99
  36. package/dist/sync-nSLnVhKK.mjs.map +1 -0
  37. package/dist/user-schema-DDz5-lX5.mjs +13 -0
  38. package/dist/user-schema-DDz5-lX5.mjs.map +1 -0
  39. package/oclif.manifest.json +106 -1
  40. package/package.json +6 -5
  41. package/dist/oclif-BoUVygsZ.mjs.map +0 -1
  42. package/dist/orca-DU8myWGm.mjs.map +0 -1
  43. package/dist/sync-B8Z2it_E.mjs.map +0 -1
@@ -1,15 +1,97 @@
1
- import { D as toZitadelError, E as ZitadelError, b as publicCliCommand, n as DEFAULT_SERVER, t as BaseCommand } from "../oclif-BoUVygsZ.mjs";
2
- import { i as issuerFromPort, n as inspectScaffoldTarget, r as RENDERER_IDS, t as createOrca } from "../orca-DU8myWGm.mjs";
3
- import { n as hasZitadelSecret, t as hasZitadelConfig } from "../project-B1qVQMKS.mjs";
4
- import { t as listListeningPorts } from "../ports-B09RjuHx.mjs";
1
+ import { D as toZitadelError, E as ZitadelError, T as stableStringify, b as publicCliCommand, n as DEFAULT_SERVER, t as BaseCommand } from "../oclif-Bm-FkF6z.mjs";
2
+ import { i as issuerFromPort, n as inspectScaffoldTarget, r as RENDERER_IDS, t as createOrca } from "../orca-CpXj_XsA.mjs";
3
+ import { n as hasZitadelSecret, t as hasZitadelConfig } from "../project-Dk7V0xka.mjs";
4
+ import { c as FLOWS_DIR, i as hashResourceContent, o as updateState } from "../sync-nSLnVhKK.mjs";
5
+ import { t as SCHEMAS_DIR } from "../user-schema-DDz5-lX5.mjs";
6
+ import { t as listListeningPorts } from "../ports-CxBKS1ga.mjs";
7
+ import { mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
8
+ import { basename, dirname, join } from "node:path";
5
9
  import { cancel, confirm, intro, isCancel, outro, select, spinner, text } from "@clack/prompts";
6
10
  import { Flags } from "@oclif/core";
7
11
  import { createZitadelClient } from "@zitadel/api/client";
8
12
  import { consola as consola$1 } from "consola";
9
- import { basename, join } from "node:path";
10
- import { readFile, stat } from "node:fs/promises";
11
13
  import { spawn } from "node:child_process";
14
+ import { DEFAULT_FLOW_CONFIG_PATH, DEFAULT_FLOW_SCHEMA_URI, DEFAULT_SCHEMA_CONFIG_PATH, flowsReadmeContent, getDefaultHumanUserSchema, getDefaultLoginFlow, schemasReadmeContent } from "@zitadel/config/defaults";
12
15
  import pc from "picocolors";
16
+ //#region src/lib/setup-resources.ts
17
+ /**
18
+ * Scaffolds the versioned local default resources for a new project, uploads
19
+ * them through the schema/flow APIs, and seeds `.zitadel/state.json` with the
20
+ * IDs, hashes, and flow metadata the sync engine expects. Setup calls this only
21
+ * after the framework patcher has created `.zitadel/{flows,schemas}` and the
22
+ * initial state file.
23
+ *
24
+ * The schema is uploaded without an `$id`: the server assigns an opaque id on
25
+ * `POST /schemas`, and the flow file can only be rendered after that id comes
26
+ * back because `flow_definition.user_schema` must reference it.
27
+ */
28
+ async function materializeSetupResources(opts) {
29
+ await mkdir(join(opts.cwd, FLOWS_DIR), { recursive: true });
30
+ await mkdir(join(opts.cwd, SCHEMAS_DIR), { recursive: true });
31
+ const filesWritten = [];
32
+ const { $id: _templateId, ...schemaBody } = getDefaultHumanUserSchema();
33
+ if (await writeResourceFile(opts.cwd, DEFAULT_SCHEMA_CONFIG_PATH, schemaBody, opts.force)) filesWritten.push(join(opts.cwd, DEFAULT_SCHEMA_CONFIG_PATH));
34
+ const schemaId = requiredString((await opts.client.createSchema(schemaBody, { project_id: opts.projectId })).id, "created schema id");
35
+ await updateState(opts.cwd, DEFAULT_SCHEMA_CONFIG_PATH, {
36
+ id: schemaId,
37
+ hash: hashWrittenBody(schemaBody)
38
+ });
39
+ const flowBody = getDefaultLoginFlow({ userSchemaUrl: schemaId });
40
+ if (await writeResourceFile(opts.cwd, DEFAULT_FLOW_CONFIG_PATH, flowBody, opts.force)) filesWritten.push(join(opts.cwd, DEFAULT_FLOW_CONFIG_PATH));
41
+ const flow = await opts.client.createFlowDefinition({
42
+ project_id: opts.projectId,
43
+ schema_uri: DEFAULT_FLOW_SCHEMA_URI,
44
+ flow_definition: flowBody
45
+ });
46
+ await updateState(opts.cwd, DEFAULT_FLOW_CONFIG_PATH, {
47
+ id: requiredString(flow.id, "created flow definition id"),
48
+ hash: hashWrittenBody(flowBody),
49
+ name: flowBody.name,
50
+ status: flowBody.status
51
+ });
52
+ const schemasReadme = join(SCHEMAS_DIR, "README.md");
53
+ const flowsReadme = join(FLOWS_DIR, "README.md");
54
+ if (await writeReadmeFile(opts.cwd, schemasReadme, schemasReadmeContent())) filesWritten.push(join(opts.cwd, schemasReadme));
55
+ if (await writeReadmeFile(opts.cwd, flowsReadme, flowsReadmeContent())) filesWritten.push(join(opts.cwd, flowsReadme));
56
+ return { filesWritten };
57
+ }
58
+ /**
59
+ * Write a README file, but never overwrite an existing one. A developer who
60
+ * has edited the README should keep their edits when `setup --force` is
61
+ * re-run.
62
+ */
63
+ async function writeReadmeFile(cwd, relPath, content) {
64
+ const dest = join(cwd, relPath);
65
+ await mkdir(dirname(dest), { recursive: true });
66
+ try {
67
+ await writeFile(dest, content, { flag: "wx" });
68
+ return true;
69
+ } catch (error) {
70
+ if (isErrno(error, "EEXIST")) return false;
71
+ throw error;
72
+ }
73
+ }
74
+ async function writeResourceFile(cwd, relPath, body, force) {
75
+ const contents = `${stableStringify(body)}\n`;
76
+ try {
77
+ await writeFile(join(cwd, relPath), contents, force ? void 0 : { flag: "wx" });
78
+ return true;
79
+ } catch (error) {
80
+ if (isErrno(error, "EEXIST")) throw new ZitadelError("E_CONFLICT", `${relPath} already exists`, { hint: "Move the file aside or rerun setup with --force if you want setup to replace it." });
81
+ throw error;
82
+ }
83
+ }
84
+ function hashWrittenBody(body) {
85
+ return hashResourceContent(JSON.parse(stableStringify(body)));
86
+ }
87
+ function requiredString(value, label) {
88
+ if (typeof value === "string" && value.length > 0) return value;
89
+ throw new ZitadelError("E_VALIDATION", `Missing ${label} in server response.`);
90
+ }
91
+ function isErrno(error, code) {
92
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
93
+ }
94
+ //#endregion
13
95
  //#region src/lib/package-manager.ts
14
96
  async function detectPackageManager(cwd) {
15
97
  const declared = await packageManagerFromManifest(cwd);
@@ -511,9 +593,9 @@ const FRAMEWORK_OPTIONS = createOrca().availableFrameworks().map((framework) =>
511
593
  *
512
594
  * Detects (or, for an empty directory, scaffolds then re-detects) the
513
595
  * framework, runs the wizard prompts to fill in any answers not pre-supplied
514
- * by flags, creates the remote project (whose default user schema and login
515
- * flow are provisioned server-side), and patches the local files via
516
- * `Orca`'s framework patcher.
596
+ * by flags, creates the remote project without server fallback defaults,
597
+ * patches the local files via `Orca`'s framework patcher, then scaffolds and
598
+ * uploads editable schema/flow config from `.zitadel/**`.
517
599
  *
518
600
  * Every interactive question lives in {@link SETUP_PROMPTS} (the main wizard
519
601
  * — each entry is a small class) and {@link PickFrameworkPrompt} (the
@@ -626,10 +708,36 @@ var Setup = class Setup extends BaseCommand {
626
708
  if (sentence) consola$1.info(sentence);
627
709
  }
628
710
  for (const file of result.filesSkipped) consola$1.info(`Left ${relativeDisplay(cwd, file)} unchanged (already matches target)`);
629
- consola$1.success(`Patched ${result.filesWritten.length} file${result.filesWritten.length === 1 ? "" : "s"}` + (result.filesSkipped.length > 0 ? ` (${result.filesSkipped.length} unchanged)` : ""));
711
+ let resourceResult;
712
+ try {
713
+ resourceResult = dryRun ? { filesWritten: [] } : await materializeSetupResources({
714
+ cwd,
715
+ client: createZitadelClient({
716
+ baseUrl: answers.server,
717
+ token: project.projectSecret
718
+ }),
719
+ projectId: project.id,
720
+ force
721
+ });
722
+ } catch (error) {
723
+ await rm(join(cwd, "zitadel.json"), { force: true });
724
+ await rm(join(cwd, ".zitadel/secret"), { force: true });
725
+ const cause = toZitadelError(error);
726
+ throw new ZitadelError(cause.code, `Default resource setup failed: ${cause.message}`, {
727
+ hint: "The project was created but its default schema/flow upload did not finish. Re-run `zitadel setup` to start over (add --force to overwrite partially written .zitadel files).",
728
+ nextCommands: ["zitadel setup --force"],
729
+ details: cause.details
730
+ });
731
+ }
732
+ for (const file of resourceResult.filesWritten) {
733
+ const sentence = describeWrittenFile(relativeDisplay(cwd, file), dryRun);
734
+ if (sentence) consola$1.info(sentence);
735
+ }
736
+ const allFilesWritten = [...result.filesWritten, ...resourceResult.filesWritten];
737
+ consola$1.success(`Patched ${allFilesWritten.length} file${allFilesWritten.length === 1 ? "" : "s"}` + (result.filesSkipped.length > 0 ? ` (${result.filesSkipped.length} unchanged)` : ""));
630
738
  this.recordTelemetry({
631
739
  step: "files_patched",
632
- files_written_count: result.filesWritten.length
740
+ files_written_count: allFilesWritten.length
633
741
  });
634
742
  const installOutcome = await installDependenciesForSetup({
635
743
  cwd,
@@ -645,7 +753,7 @@ var Setup = class Setup extends BaseCommand {
645
753
  step: "dependencies_installed",
646
754
  package_manager: installOutcome.install.package_manager
647
755
  });
648
- const writtenRel = result.filesWritten.map((file) => relativeDisplay(cwd, file));
756
+ const writtenRel = allFilesWritten.map((file) => relativeDisplay(cwd, file));
649
757
  if (!this.jsonEnabled()) {
650
758
  const sections = buildSummary({
651
759
  projectFacts: await detectProjectFacts(cwd, framework.id),
@@ -680,7 +788,7 @@ var Setup = class Setup extends BaseCommand {
680
788
  },
681
789
  framework: framework.id,
682
790
  server: answers.server,
683
- files_written: result.filesWritten.map((file) => relativeDisplay(cwd, file)),
791
+ files_written: allFilesWritten.map((file) => relativeDisplay(cwd, file)),
684
792
  files_skipped: result.filesSkipped.map((file) => relativeDisplay(cwd, file)),
685
793
  install: installOutcome.install,
686
794
  next_actions: installOutcome.nextActions,
@@ -721,7 +829,10 @@ function dryRunProject(issuer) {
721
829
  }
722
830
  async function createProjectWithLocalHint(client, server, cliVersion, issuer, framework) {
723
831
  try {
724
- return await client.createProject({ previewOrigins: [issuer] });
832
+ return await client.createProject({
833
+ previewOrigins: [issuer],
834
+ seedDefaults: false
835
+ });
725
836
  } catch (error) {
726
837
  const normalized = toZitadelError(error);
727
838
  throw new ZitadelError(normalized.code, normalized.message, {
@@ -794,7 +905,11 @@ const SENTENCE_BY_PATH = {
794
905
  "zitadel.json": { subject: "the Zitadel project configuration" },
795
906
  ".env.example": { subject: "the .env example template" },
796
907
  ".env.local": { subject: "the local development environment variables" },
797
- ".zitadel/state.json": { subject: "the empty sync state file" },
908
+ ".zitadel/state.json": { subject: "the sync state file" },
909
+ ".zitadel/flows/default-login.json": { subject: "the editable default login flow" },
910
+ ".zitadel/flows/README.md": { subject: "the flows folder README" },
911
+ ".zitadel/schemas/default-human-user.json": { subject: "the editable default human user schema" },
912
+ ".zitadel/schemas/README.md": { subject: "the schemas folder README" },
798
913
  "app/page.tsx": { subject: "the auth home page" },
799
914
  "app/login/page.tsx": { subject: "the login page" },
800
915
  "app/register/page.tsx": { subject: "the registration page" },
@@ -1 +1 @@
1
- {"version":3,"file":"setup.mjs","names":["stylePath","styleId","styleUrl"],"sources":["../../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/lib/prober/http.ts","../../src/commands/setup/prompts/server.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 { 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 {\n detectPackageManager,\n devCommandFor,\n installCommandFor,\n runPackageCommand,\n type PackageCommand,\n type PackageManager,\n} from \"../../lib/package-manager\";\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 nextActions: string[];\n nextCommands: string[];\n};\n\nexport type SetupInstallInput = {\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 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 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 issuer: input.issuer,\n includeInstallCommand: false,\n });\n}\n\nfunction outcome(input: {\n install: SetupInstall;\n devCommand: string;\n issuer: string;\n includeInstallCommand: boolean;\n}): SetupInstallOutcome {\n const startAction = `Start your project: ${input.devCommand} (then open ${input.issuer})`;\n const verifyAction =\n \"Verify auth in the browser: register a user, log out, log in again with the same user, and confirm /profile shows Signed in.\";\n return {\n install: input.install,\n devCommand: input.devCommand,\n nextActions: input.includeInstallCommand\n ? [`Install dependencies: ${input.install.command}`, startAction, verifyAction]\n : [startAction, verifyAction],\n nextCommands: input.includeInstallCommand\n ? [input.install.command, input.devCommand]\n : [input.devCommand],\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 type { ProbeMatch, ProbePredicate } from \"./types\";\n\n/**\n * Fetch `url` with a per-call timeout and pass the resulting `Response` to\n * `predicate`. Returns the predicate's value, or `null` on any failure: a\n * network error, an `AbortError` from the timeout, a thrown predicate, or the\n * predicate returning `null`.\n *\n * Never throws. The predicate decides what counts as a match — it gets the\n * raw `Response` and may read `.json()` / `.headers` / `.status` as needed.\n *\n * `timeoutMs` defaults to 500ms. The implementation uses\n * `AbortSignal.timeout`, so the underlying fetch is cancelled when the\n * timeout fires (no orphaned sockets).\n */\nexport async function probeUrl<T>(\n url: string,\n predicate: ProbePredicate<T>,\n opts?: { readonly timeoutMs?: number },\n): Promise<T | null> {\n const timeoutMs = opts?.timeoutMs ?? 500;\n try {\n const response = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) });\n return await predicate(response);\n } catch {\n return null;\n }\n}\n\n/**\n * Probe many URLs in parallel and return the non-null matches, preserving\n * the input order. Each URL is bounded by `timeoutMs` independently — one\n * slow target can't hold up the others.\n */\nexport async function probeUrls<T>(\n urls: Iterable<string>,\n predicate: ProbePredicate<T>,\n opts?: { readonly timeoutMs?: number },\n): Promise<ReadonlyArray<ProbeMatch<T>>> {\n const list = [...urls];\n const results = await Promise.all(\n list.map(async (url): Promise<ProbeMatch<T> | null> => {\n const value = await probeUrl(url, predicate, opts);\n return value === null ? null : { url, value };\n }),\n );\n return results.filter((match): match is ProbeMatch<T> => match !== null);\n}\n","import { select, spinner, text } from \"@clack/prompts\";\n\nimport { DEFAULT_SERVER } from \"../../../lib/server\";\nimport { listListeningPorts, probeUrls } from \"../../../lib/prober\";\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/** Per-probe timeout for the localhost OIDC scan — generous enough for a TLS handshake on a busy laptop. */\nconst OIDC_PROBE_TIMEOUT_MS = 300;\n\n/**\n * \"Which server should `zitadel.json` point to?\" — Zitadel Cloud, a localhost\n * OIDC server we discovered, or a custom URL.\n *\n * Before asking, it scans the loopback for listening ports (via the generic\n * `lib/prober`) and `GET`s `/.well-known/openid-configuration` on each. Every\n * 2xx response with a string `issuer` becomes an extra option in the choice\n * list. Picking a discovered URL writes it directly to `answers.server` and\n * skips the follow-up text prompt. 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 / discovered / Custom) was a bug —\n // clack would silently default back to Cloud.\n if (ctx.serverFlag) {\n return answers;\n }\n const discovered = await discoverLocalOidc();\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 ...discovered.map((server) => ({\n value: server,\n label: server,\n hint: \"detected — OIDC\",\n })),\n { value: CUSTOM, label: \"Custom URL (self-hosted)\" },\n ],\n initialValue: 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 * Returns the loopback origins (`http://localhost:<port>`) whose\n * `/.well-known/openid-configuration` endpoint responds with a valid OIDC\n * discovery document. Sniffs purely via the generic prober — the only\n * Zitadel-shaped detail here is the OIDC predicate, which is the standard\n * \"any OIDC server\" contract (no `zitadel`-keyword check), so Keycloak/dex/\n * etc. also surface and the user picks the right one.\n */\nasync function discoverLocalOidc(): Promise<ReadonlyArray<string>> {\n const s = spinner();\n s.start(\"Scanning localhost for OIDC servers\");\n try {\n const ports = await listListeningPorts();\n if (ports.length === 0) {\n s.stop(\"No local servers detected.\");\n return [];\n }\n const matches = await probeUrls(\n ports.map((port) => `http://localhost:${port}/.well-known/openid-configuration`),\n async (response) => {\n if (!response.ok) {\n return null;\n }\n try {\n const body = (await response.json()) as { issuer?: unknown };\n return typeof body.issuer === \"string\" ? body.issuer : null;\n } catch {\n return null;\n }\n },\n { timeoutMs: OIDC_PROBE_TIMEOUT_MS },\n );\n const origins = matches.map((match) => new URL(match.url).origin);\n s.stop(\n origins.length === 0\n ? \"No local OIDC servers found.\"\n : `Found ${origins.length} local OIDC server${origins.length === 1 ? \"\" : \"s\"}.`,\n );\n return origins;\n } catch (error) {\n s.stop(\"Discovery skipped.\");\n throw error;\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 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 { 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];\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 { 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 { 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 { 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 (whose default user schema and login\n * flow are provisioned server-side), and patches the local files via\n * `Orca`'s framework patcher.\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 };\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, flags.framework, 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 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 };\n\n if (!nonInteractive && !dryRun) {\n intro(\"Zitadel setup\");\n const promptCtx = {\n framework,\n serverFlag: this.meta.serverFlag,\n devPortFromFlag: flags[\"dev-port\"] !== undefined,\n };\n for (const prompt of SETUP_PROMPTS) {\n answers = await prompt.ask(answers, promptCtx);\n }\n outro(\"Configuration captured\");\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. Creating the project also\n // provisions its default user schema and login flow server-side, so the\n // CLI no longer builds, scaffolds, or uploads those resources here.\n consola.start(`Creating project on ${answers.server}${dryRun ? \" (dry run)\" : \"\"}`);\n const unauthClient = createZitadelClient({ baseUrl: answers.server });\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 issuer,\n framework.id,\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 };\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 consola.success(\n `Patched ${result.filesWritten.length} file${result.filesWritten.length === 1 ? \"\" : \"s\"}` +\n (result.filesSkipped.length > 0 ? ` (${result.filesSkipped.length} unchanged)` : \"\"),\n );\n this.recordTelemetry({\n step: \"files_patched\",\n files_written_count: result.filesWritten.length,\n });\n\n const installOutcome = await installDependenciesForSetup({\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 = result.filesWritten.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.nextActions.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: result.filesWritten.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\nasync function createProjectWithLocalHint(\n client: ReturnType<typeof createZitadelClient>,\n server: string,\n cliVersion: string,\n issuer: string,\n framework: string,\n): Promise<CreateProject201> {\n try {\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({ previewOrigins: [issuer] });\n } catch (error) {\n const normalized = toZitadelError(error);\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 --framework ${framework} --server local.`,\n nextCommands: [\n publicCliCommand(\"start\", cliVersion),\n publicCliCommand(`setup --framework ${framework} --server local`, cliVersion),\n ],\n details: {\n server,\n original: normalized.details,\n },\n });\n }\n}\n\nfunction localSetupHint(error: unknown, framework: string | undefined, 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 = framework\n ? `setup --framework ${framework} --server local`\n : \"setup --server local\";\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 (relPath === \".zitadel\" || relPath === \".zitadel/flows\" || relPath === \".zitadel/schemas\") {\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 empty sync state file\" },\n \"app/page.tsx\": { subject: \"the auth home page\" },\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 page\", \"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":["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/lib/prober/http.ts","../../src/commands/setup/prompts/server.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 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 flowsReadmeContent,\n getDefaultHumanUserSchema,\n getDefaultLoginFlow,\n schemasReadmeContent,\n} from \"@zitadel/config/defaults\";\n\nimport { FLOWS_DIR } from \"./flows\";\nimport { stableStringify } from \"./json\";\nimport { hashResourceContent } 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}): 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\n const { $id: _templateId, ...schemaBody } = getDefaultHumanUserSchema() 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 await updateState(opts.cwd, DEFAULT_SCHEMA_CONFIG_PATH, {\n id: schemaId,\n hash: hashWrittenBody(schemaBody),\n });\n\n const flowBody = getDefaultLoginFlow({ userSchemaUrl: schemaId });\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 await updateState(opts.cwd, DEFAULT_FLOW_CONFIG_PATH, {\n id: requiredString(flow.id, \"created flow definition id\"),\n hash: hashWrittenBody(flowBody),\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 hashWrittenBody(body: object): string {\n // Match the exact normalized JSON shape written to disk so setup-seeded\n // state is immediately comparable with the sync planner.\n return hashResourceContent(JSON.parse(stableStringify(body)) as object);\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 {\n detectPackageManager,\n devCommandFor,\n installCommandFor,\n runPackageCommand,\n type PackageCommand,\n type PackageManager,\n} from \"../../lib/package-manager\";\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 nextActions: string[];\n nextCommands: string[];\n};\n\nexport type SetupInstallInput = {\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 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 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 issuer: input.issuer,\n includeInstallCommand: false,\n });\n}\n\nfunction outcome(input: {\n install: SetupInstall;\n devCommand: string;\n issuer: string;\n includeInstallCommand: boolean;\n}): SetupInstallOutcome {\n const startAction = `Start your project: ${input.devCommand} (then open ${input.issuer})`;\n const verifyAction =\n \"Verify auth in the browser: register a user, log out, log in again with the same user, and confirm /profile shows Signed in.\";\n return {\n install: input.install,\n devCommand: input.devCommand,\n nextActions: input.includeInstallCommand\n ? [`Install dependencies: ${input.install.command}`, startAction, verifyAction]\n : [startAction, verifyAction],\n nextCommands: input.includeInstallCommand\n ? [input.install.command, input.devCommand]\n : [input.devCommand],\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 type { ProbeMatch, ProbePredicate } from \"./types\";\n\n/**\n * Fetch `url` with a per-call timeout and pass the resulting `Response` to\n * `predicate`. Returns the predicate's value, or `null` on any failure: a\n * network error, an `AbortError` from the timeout, a thrown predicate, or the\n * predicate returning `null`.\n *\n * Never throws. The predicate decides what counts as a match — it gets the\n * raw `Response` and may read `.json()` / `.headers` / `.status` as needed.\n *\n * `timeoutMs` defaults to 500ms. The implementation uses\n * `AbortSignal.timeout`, so the underlying fetch is cancelled when the\n * timeout fires (no orphaned sockets).\n */\nexport async function probeUrl<T>(\n url: string,\n predicate: ProbePredicate<T>,\n opts?: { readonly timeoutMs?: number },\n): Promise<T | null> {\n const timeoutMs = opts?.timeoutMs ?? 500;\n try {\n const response = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) });\n return await predicate(response);\n } catch {\n return null;\n }\n}\n\n/**\n * Probe many URLs in parallel and return the non-null matches, preserving\n * the input order. Each URL is bounded by `timeoutMs` independently — one\n * slow target can't hold up the others.\n */\nexport async function probeUrls<T>(\n urls: Iterable<string>,\n predicate: ProbePredicate<T>,\n opts?: { readonly timeoutMs?: number },\n): Promise<ReadonlyArray<ProbeMatch<T>>> {\n const list = [...urls];\n const results = await Promise.all(\n list.map(async (url): Promise<ProbeMatch<T> | null> => {\n const value = await probeUrl(url, predicate, opts);\n return value === null ? null : { url, value };\n }),\n );\n return results.filter((match): match is ProbeMatch<T> => match !== null);\n}\n","import { select, spinner, text } from \"@clack/prompts\";\n\nimport { DEFAULT_SERVER } from \"../../../lib/server\";\nimport { listListeningPorts, probeUrls } from \"../../../lib/prober\";\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/** Per-probe timeout for the localhost OIDC scan — generous enough for a TLS handshake on a busy laptop. */\nconst OIDC_PROBE_TIMEOUT_MS = 300;\n\n/**\n * \"Which server should `zitadel.json` point to?\" — Zitadel Cloud, a localhost\n * OIDC server we discovered, or a custom URL.\n *\n * Before asking, it scans the loopback for listening ports (via the generic\n * `lib/prober`) and `GET`s `/.well-known/openid-configuration` on each. Every\n * 2xx response with a string `issuer` becomes an extra option in the choice\n * list. Picking a discovered URL writes it directly to `answers.server` and\n * skips the follow-up text prompt. 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 / discovered / Custom) was a bug —\n // clack would silently default back to Cloud.\n if (ctx.serverFlag) {\n return answers;\n }\n const discovered = await discoverLocalOidc();\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 ...discovered.map((server) => ({\n value: server,\n label: server,\n hint: \"detected — OIDC\",\n })),\n { value: CUSTOM, label: \"Custom URL (self-hosted)\" },\n ],\n initialValue: 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 * Returns the loopback origins (`http://localhost:<port>`) whose\n * `/.well-known/openid-configuration` endpoint responds with a valid OIDC\n * discovery document. Sniffs purely via the generic prober — the only\n * Zitadel-shaped detail here is the OIDC predicate, which is the standard\n * \"any OIDC server\" contract (no `zitadel`-keyword check), so Keycloak/dex/\n * etc. also surface and the user picks the right one.\n */\nasync function discoverLocalOidc(): Promise<ReadonlyArray<string>> {\n const s = spinner();\n s.start(\"Scanning localhost for OIDC servers\");\n try {\n const ports = await listListeningPorts();\n if (ports.length === 0) {\n s.stop(\"No local servers detected.\");\n return [];\n }\n const matches = await probeUrls(\n ports.map((port) => `http://localhost:${port}/.well-known/openid-configuration`),\n async (response) => {\n if (!response.ok) {\n return null;\n }\n try {\n const body = (await response.json()) as { issuer?: unknown };\n return typeof body.issuer === \"string\" ? body.issuer : null;\n } catch {\n return null;\n }\n },\n { timeoutMs: OIDC_PROBE_TIMEOUT_MS },\n );\n const origins = matches.map((match) => new URL(match.url).origin);\n s.stop(\n origins.length === 0\n ? \"No local OIDC servers found.\"\n : `Found ${origins.length} local OIDC server${origins.length === 1 ? \"\" : \"s\"}.`,\n );\n return origins;\n } catch (error) {\n s.stop(\"Discovery skipped.\");\n throw error;\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 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 { 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];\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 { 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 { 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 };\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, flags.framework, 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 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 };\n\n if (!nonInteractive && !dryRun) {\n intro(\"Zitadel setup\");\n const promptCtx = {\n framework,\n serverFlag: this.meta.serverFlag,\n devPortFromFlag: flags[\"dev-port\"] !== undefined,\n };\n for (const prompt of SETUP_PROMPTS) {\n answers = await prompt.ask(answers, promptCtx);\n }\n outro(\"Configuration captured\");\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 // 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 issuer,\n framework.id,\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 };\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 });\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 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.nextActions.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\nasync function createProjectWithLocalHint(\n client: ReturnType<typeof createZitadelClient>,\n server: string,\n cliVersion: string,\n issuer: string,\n framework: string,\n): Promise<CreateProject201> {\n try {\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({ previewOrigins: [issuer], seedDefaults: false });\n } catch (error) {\n const normalized = toZitadelError(error);\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 --framework ${framework} --server local.`,\n nextCommands: [\n publicCliCommand(\"start\", cliVersion),\n publicCliCommand(`setup --framework ${framework} --server local`, cliVersion),\n ],\n details: {\n server,\n original: normalized.details,\n },\n });\n }\n}\n\nfunction localSetupHint(error: unknown, framework: string | undefined, 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 = framework\n ? `setup --framework ${framework} --server local`\n : \"setup --server local\";\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 (relPath === \".zitadel\" || relPath === \".zitadel/flows\" || relPath === \".zitadel/schemas\") {\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 \"app/page.tsx\": { subject: \"the auth home page\" },\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 page\", \"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,7 +1,7 @@
1
- import { D as toZitadelError, E as ZitadelError, a as DEFAULT_LOCAL_SERVER_PORT, b as publicCliCommand, c as checkLocalServerHealth, d as ensureLocalState, f as localContainerName, l as defaultLocalServerImageForCliVersion, m as readRuntimeMetadata, p as localServerUrl, t as BaseCommand, u as ensureContainerIdentity, v as writeRuntimeMetadata } from "../oclif-BoUVygsZ.mjs";
2
- import { n as listenersForPort } from "../ports-B09RjuHx.mjs";
3
- 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-Djz6BLp9.mjs";
4
- import { n as dockerUnavailableMessage, t as dockerRuntimeGuidance } from "../docker-guidance-D-33g1uV.mjs";
1
+ import { D as toZitadelError, E as ZitadelError, a as DEFAULT_LOCAL_SERVER_PORT, b as publicCliCommand, c as checkLocalServerHealth, d as ensureLocalState, f as localContainerName, l as defaultLocalServerImageForCliVersion, m as readRuntimeMetadata, p as localServerUrl, t as BaseCommand, u as ensureContainerIdentity, v as writeRuntimeMetadata } from "../oclif-Bm-FkF6z.mjs";
2
+ import { n as listenersForPort } from "../ports-CxBKS1ga.mjs";
3
+ 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-D7BSD5C9.mjs";
4
+ import { n as dockerUnavailableMessage, t as dockerRuntimeGuidance } from "../docker-guidance-mcTT3_0E.mjs";
5
5
  import { Flags } from "@oclif/core";
6
6
  import { setTimeout } from "node:timers/promises";
7
7
  //#region src/commands/start.ts
@@ -1,6 +1,6 @@
1
- import { S as resolveCwd, _ as runtimeSummary, b as publicCliCommand, c as checkLocalServerHealth, m as readRuntimeMetadata, t as BaseCommand } from "../oclif-BoUVygsZ.mjs";
2
- import { a as readZitadelConfig, n as hasZitadelSecret, o as readZitadelSecret, r as readDevelopmentIssuer, t as hasZitadelConfig } from "../project-B1qVQMKS.mjs";
3
- import { m as isProcessRunning, s as inspectContainer } from "../docker-Djz6BLp9.mjs";
1
+ import { S as resolveCwd, _ as runtimeSummary, b as publicCliCommand, c as checkLocalServerHealth, m as readRuntimeMetadata, t as BaseCommand } from "../oclif-Bm-FkF6z.mjs";
2
+ import { a as readZitadelConfig, n as hasZitadelSecret, o as readZitadelSecret, r as readDevelopmentIssuer, t as hasZitadelConfig } from "../project-Dk7V0xka.mjs";
3
+ import { m as isProcessRunning, s as inspectContainer } from "../docker-D7BSD5C9.mjs";
4
4
  //#region src/commands/status.ts
5
5
  /**
6
6
  * `zitadel status` — summarize the local server and project state.
@@ -1,6 +1,6 @@
1
- import { E as ZitadelError, S as resolveCwd, b as publicCliCommand, f as localContainerName, m as readRuntimeMetadata, t as BaseCommand } from "../oclif-BoUVygsZ.mjs";
2
- import { g as stopBinaryRuntime, u as stopAndRemoveContainer } from "../docker-Djz6BLp9.mjs";
3
- import { t as discoverManagedRuntimeProcesses } from "../processes-Cw8TO1SY.mjs";
1
+ import { E as ZitadelError, S as resolveCwd, b as publicCliCommand, f as localContainerName, m as readRuntimeMetadata, t as BaseCommand } from "../oclif-Bm-FkF6z.mjs";
2
+ import { g as stopBinaryRuntime, u as stopAndRemoveContainer } from "../docker-D7BSD5C9.mjs";
3
+ import { t as discoverManagedRuntimeProcesses } from "../processes-BVqYsxT8.mjs";
4
4
  import { Flags } from "@oclif/core";
5
5
  //#region src/commands/stop.ts
6
6
  var Stop = class Stop extends BaseCommand {
@@ -1,7 +1,7 @@
1
- import { E as ZitadelError, i as CONTAINER_HTTP_PORT, r as CONTAINER_DATA_DIR } from "./oclif-BoUVygsZ.mjs";
1
+ import { E as ZitadelError, i as CONTAINER_HTTP_PORT, r as CONTAINER_DATA_DIR } from "./oclif-Bm-FkF6z.mjs";
2
2
  import { createRequire } from "node:module";
3
- import { dirname, join } from "node:path";
4
3
  import { mkdir, open, readFile, stat } from "node:fs/promises";
4
+ import { dirname, join } from "node:path";
5
5
  import { createReadStream } from "node:fs";
6
6
  import { spawn } from "node:child_process";
7
7
  //#region src/lib/local-server/binary.ts
@@ -429,4 +429,4 @@ function dockerError(action, args, cause) {
429
429
  //#endregion
430
430
  export { followContainerLogs as a, metadataFromStart as c, assertServerPackageAvailable as d, binaryLogs as f, stopBinaryRuntime as g, startBinaryRuntime as h, ensureImage as i, startContainer as l, isProcessRunning as m, currentUser as n, imageAvailable as o, followBinaryLogs as p, dockerAvailable as r, inspectContainer as s, containerLogs as t, stopAndRemoveContainer as u };
431
431
 
432
- //# sourceMappingURL=docker-Djz6BLp9.mjs.map
432
+ //# sourceMappingURL=docker-D7BSD5C9.mjs.map