@zitadel/cli 0.1.0-alpha.0 → 0.1.0-alpha.2

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 (35) hide show
  1. package/README.md +158 -24
  2. package/SKILLS.md +40 -8
  3. package/dist/commands/apply.mjs +4 -3
  4. package/dist/commands/apply.mjs.map +1 -1
  5. package/dist/commands/doctor.mjs +150 -16
  6. package/dist/commands/doctor.mjs.map +1 -1
  7. package/dist/commands/eject.mjs +4 -3
  8. package/dist/commands/eject.mjs.map +1 -1
  9. package/dist/commands/logs.mjs +50 -0
  10. package/dist/commands/logs.mjs.map +1 -0
  11. package/dist/commands/plan.mjs +4 -3
  12. package/dist/commands/plan.mjs.map +1 -1
  13. package/dist/commands/reset.mjs +62 -0
  14. package/dist/commands/reset.mjs.map +1 -0
  15. package/dist/commands/setup.mjs +189 -23
  16. package/dist/commands/setup.mjs.map +1 -1
  17. package/dist/commands/start.mjs +128 -0
  18. package/dist/commands/start.mjs.map +1 -0
  19. package/dist/commands/status.mjs +74 -27
  20. package/dist/commands/status.mjs.map +1 -1
  21. package/dist/commands/stop.mjs +43 -0
  22. package/dist/commands/stop.mjs.map +1 -0
  23. package/dist/docker-DrOBycgG.mjs +210 -0
  24. package/dist/docker-DrOBycgG.mjs.map +1 -0
  25. package/dist/{project-C3pSfbao.mjs → oclif-CqkWBQ7i.mjs} +300 -119
  26. package/dist/oclif-CqkWBQ7i.mjs.map +1 -0
  27. package/dist/{orca-COsUnVoz.mjs → orca-S1tVnngd.mjs} +41 -12
  28. package/dist/{orca-COsUnVoz.mjs.map → orca-S1tVnngd.mjs.map} +1 -1
  29. package/dist/project-B6YfSaZw.mjs +87 -0
  30. package/dist/project-B6YfSaZw.mjs.map +1 -0
  31. package/dist/{sync-Cuyh-X1J.mjs → sync-DN4oNLVH.mjs} +4 -4
  32. package/dist/{sync-Cuyh-X1J.mjs.map → sync-DN4oNLVH.mjs.map} +1 -1
  33. package/oclif.manifest.json +357 -3
  34. package/package.json +3 -3
  35. package/dist/project-C3pSfbao.mjs.map +0 -1
@@ -0,0 +1,128 @@
1
+ import { E as ZitadelError, a as DEFAULT_LOCAL_SERVER_PORT, b as writeRuntimeMetadata, c as checkLocalServerHealth, d as ensureLocalState, h as localServerUrl, l as defaultLocalServerImageForCliVersion, p as localContainerName, t as BaseCommand, u as ensureContainerIdentity, x as publicCliCommand } from "../oclif-CqkWBQ7i.mjs";
2
+ import { c as metadataFromStart, i as ensureImage, l as startContainer, n as currentUser, s as inspectContainer, u as stopAndRemoveContainer } from "../docker-DrOBycgG.mjs";
3
+ import { Flags } from "@oclif/core";
4
+ import { setTimeout } from "node:timers/promises";
5
+ //#region src/commands/start.ts
6
+ const START_TIMEOUT_MS = 9e4;
7
+ var Start = class Start extends BaseCommand {
8
+ static description = "Start a local Zitadel server.";
9
+ static flags = {
10
+ image: Flags.string({ description: "Container image to run." }),
11
+ port: Flags.integer({
12
+ description: "Local HTTP port.",
13
+ default: DEFAULT_LOCAL_SERVER_PORT
14
+ })
15
+ };
16
+ async run() {
17
+ const { flags } = await this.parse(Start);
18
+ const port = flags.port ?? 8080;
19
+ const serverUrl = localServerUrl(port);
20
+ await this.toMeta(flags, {
21
+ resolveServer: false,
22
+ source: serverUrl
23
+ });
24
+ validatePort(port);
25
+ const image = flags.image ?? this.meta.env.ZITADEL_LOCAL_IMAGE ?? defaultLocalServerImageForCliVersion(this.meta.cliVersion);
26
+ const containerName = localContainerName(this.meta.cwd);
27
+ if (this.meta.dryRun) return this.emit({
28
+ status: "ok",
29
+ data: {
30
+ title: "Local Zitadel server start plan.",
31
+ runtime: {
32
+ container_name: containerName,
33
+ image,
34
+ port
35
+ },
36
+ urls: {
37
+ api: serverUrl,
38
+ console: `${serverUrl}/ui/console/`,
39
+ login: `${serverUrl}/ui/login/`
40
+ },
41
+ next_commands: [publicCliCommand("start", this.meta.cliVersion)]
42
+ }
43
+ });
44
+ const paths = await ensureLocalState(this.meta.cwd);
45
+ const existing = await inspectContainer(containerName);
46
+ if (existing.exists && existing.running && existing.image === image && await checkLocalServerHealth(serverUrl)) {
47
+ const metadata = metadataFromStart({
48
+ cwdDataDir: paths.dataDir,
49
+ cliVersion: this.meta.cliVersion,
50
+ containerName,
51
+ containerId: existing.id ?? containerName,
52
+ image,
53
+ port,
54
+ serverUrl
55
+ });
56
+ await writeRuntimeMetadata(this.meta.cwd, metadata);
57
+ return this.emit({
58
+ status: "ok",
59
+ data: readyData(metadata, true, this.meta.cliVersion)
60
+ });
61
+ }
62
+ if (existing.exists) await stopAndRemoveContainer(containerName);
63
+ await ensureImage(image);
64
+ const containerId = await startContainer({
65
+ containerName,
66
+ image,
67
+ port,
68
+ dataDir: paths.dataDir,
69
+ identity: await ensureContainerIdentity(this.meta.cwd, currentUser())
70
+ });
71
+ await waitForHealth(serverUrl, containerName, this.meta.cliVersion);
72
+ const metadata = metadataFromStart({
73
+ cwdDataDir: paths.dataDir,
74
+ cliVersion: this.meta.cliVersion,
75
+ containerName,
76
+ containerId,
77
+ image,
78
+ port,
79
+ serverUrl
80
+ });
81
+ await writeRuntimeMetadata(this.meta.cwd, metadata);
82
+ return this.emit({
83
+ status: "ok",
84
+ data: readyData(metadata, false, this.meta.cliVersion)
85
+ });
86
+ }
87
+ };
88
+ function readyData(metadata, alreadyRunning, cliVersion) {
89
+ return {
90
+ title: alreadyRunning ? "Local Zitadel server is already running." : "Local Zitadel server is ready.",
91
+ runtime: {
92
+ container_name: metadata.container_name,
93
+ container_id: metadata.container_id,
94
+ image: metadata.image,
95
+ port: metadata.port,
96
+ data_dir: metadata.data_dir
97
+ },
98
+ urls: {
99
+ api: metadata.server_url,
100
+ console: `${metadata.server_url}/ui/console/`,
101
+ login: `${metadata.server_url}/ui/login/`
102
+ },
103
+ next_actions: ["From your app directory, run setup; the CLI will detect the framework or ask when needed.", "Setup installs dependencies when needed; then start your app dev server."],
104
+ next_commands: [publicCliCommand("setup --server local", cliVersion)]
105
+ };
106
+ }
107
+ async function waitForHealth(serverUrl, containerName, cliVersion) {
108
+ const started = Date.now();
109
+ while (Date.now() - started < START_TIMEOUT_MS) {
110
+ if (await checkLocalServerHealth(serverUrl, 1e3)) return;
111
+ await setTimeout(1e3);
112
+ }
113
+ throw new ZitadelError("E_NETWORK", "Local Zitadel server did not become healthy", {
114
+ hint: "Inspect the container logs, then reset the local runtime if needed.",
115
+ nextCommands: [publicCliCommand("logs", cliVersion), publicCliCommand("reset --force", cliVersion)],
116
+ details: {
117
+ container_name: containerName,
118
+ server_url: serverUrl
119
+ }
120
+ });
121
+ }
122
+ function validatePort(port) {
123
+ if (!Number.isInteger(port) || port < 1 || port > 65535) throw new ZitadelError("E_VALIDATION", `Invalid port ${String(port)}`, { hint: "Use a TCP port between 1 and 65535." });
124
+ }
125
+ //#endregion
126
+ export { Start as default };
127
+
128
+ //# sourceMappingURL=start.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.mjs","names":["sleep"],"sources":["../../src/commands/start.ts"],"sourcesContent":["import { setTimeout as sleep } from \"node:timers/promises\";\n\nimport { Flags } from \"@oclif/core\";\n\nimport { ZitadelError } from \"../lib/errors\";\nimport {\n currentUser,\n ensureImage,\n inspectContainer,\n metadataFromStart,\n startContainer,\n stopAndRemoveContainer,\n} from \"../lib/local-server/docker\";\nimport {\n DEFAULT_LOCAL_SERVER_PORT,\n checkLocalServerHealth,\n defaultLocalServerImageForCliVersion,\n ensureContainerIdentity,\n ensureLocalState,\n localContainerName,\n localServerUrl,\n writeRuntimeMetadata,\n} from \"../lib/local-server/runtime\";\nimport { BaseCommand, type JsonEnvelope } from \"../lib/oclif\";\nimport { publicCliCommand } from \"../lib/public-cli\";\n\nconst START_TIMEOUT_MS = 90_000;\n\nexport default class Start extends BaseCommand {\n static override description = \"Start a local Zitadel server.\";\n static override flags = {\n image: Flags.string({ description: \"Container image to run.\" }),\n port: Flags.integer({ description: \"Local HTTP port.\", default: DEFAULT_LOCAL_SERVER_PORT }),\n };\n\n async run(): Promise<JsonEnvelope> {\n const { flags } = await this.parse(Start);\n const port = flags.port ?? DEFAULT_LOCAL_SERVER_PORT;\n const serverUrl = localServerUrl(port);\n await this.toMeta(flags, { resolveServer: false, source: serverUrl });\n\n validatePort(port);\n const image =\n flags.image ??\n this.meta.env.ZITADEL_LOCAL_IMAGE ??\n defaultLocalServerImageForCliVersion(this.meta.cliVersion);\n const containerName = localContainerName(this.meta.cwd);\n if (this.meta.dryRun) {\n return this.emit({\n status: \"ok\",\n data: {\n title: \"Local Zitadel server start plan.\",\n runtime: {\n container_name: containerName,\n image,\n port,\n },\n urls: {\n api: serverUrl,\n console: `${serverUrl}/ui/console/`,\n login: `${serverUrl}/ui/login/`,\n },\n next_commands: [publicCliCommand(\"start\", this.meta.cliVersion)],\n },\n });\n }\n\n const paths = await ensureLocalState(this.meta.cwd);\n\n const existing = await inspectContainer(containerName);\n if (\n existing.exists &&\n existing.running &&\n existing.image === image &&\n (await checkLocalServerHealth(serverUrl))\n ) {\n const metadata = metadataFromStart({\n cwdDataDir: paths.dataDir,\n cliVersion: this.meta.cliVersion,\n containerName,\n containerId: existing.id ?? containerName,\n image,\n port,\n serverUrl,\n });\n await writeRuntimeMetadata(this.meta.cwd, metadata);\n return this.emit({\n status: \"ok\",\n data: readyData(metadata, true, this.meta.cliVersion),\n });\n }\n\n if (existing.exists) {\n await stopAndRemoveContainer(containerName);\n }\n\n await ensureImage(image);\n const containerId = await startContainer({\n containerName,\n image,\n port,\n dataDir: paths.dataDir,\n identity: await ensureContainerIdentity(this.meta.cwd, currentUser()),\n });\n await waitForHealth(serverUrl, containerName, this.meta.cliVersion);\n\n const metadata = metadataFromStart({\n cwdDataDir: paths.dataDir,\n cliVersion: this.meta.cliVersion,\n containerName,\n containerId,\n image,\n port,\n serverUrl,\n });\n await writeRuntimeMetadata(this.meta.cwd, metadata);\n return this.emit({\n status: \"ok\",\n data: readyData(metadata, false, this.meta.cliVersion),\n });\n }\n}\n\nfunction readyData(\n metadata: ReturnType<typeof metadataFromStart>,\n alreadyRunning: boolean,\n cliVersion: string,\n) {\n return {\n title: alreadyRunning\n ? \"Local Zitadel server is already running.\"\n : \"Local Zitadel server is ready.\",\n runtime: {\n container_name: metadata.container_name,\n container_id: metadata.container_id,\n image: metadata.image,\n port: metadata.port,\n data_dir: metadata.data_dir,\n },\n urls: {\n api: metadata.server_url,\n console: `${metadata.server_url}/ui/console/`,\n login: `${metadata.server_url}/ui/login/`,\n },\n next_actions: [\n \"From your app directory, run setup; the CLI will detect the framework or ask when needed.\",\n \"Setup installs dependencies when needed; then start your app dev server.\",\n ],\n next_commands: [publicCliCommand(\"setup --server local\", cliVersion)],\n };\n}\n\nasync function waitForHealth(\n serverUrl: string,\n containerName: string,\n cliVersion: string,\n): Promise<void> {\n const started = Date.now();\n while (Date.now() - started < START_TIMEOUT_MS) {\n if (await checkLocalServerHealth(serverUrl, 1000)) {\n return;\n }\n await sleep(1000);\n }\n throw new ZitadelError(\"E_NETWORK\", \"Local Zitadel server did not become healthy\", {\n hint: \"Inspect the container logs, then reset the local runtime if needed.\",\n nextCommands: [\n publicCliCommand(\"logs\", cliVersion),\n publicCliCommand(\"reset --force\", cliVersion),\n ],\n details: { container_name: containerName, server_url: serverUrl },\n });\n}\n\nfunction validatePort(port: number): void {\n if (!Number.isInteger(port) || port < 1 || port > 65_535) {\n throw new ZitadelError(\"E_VALIDATION\", `Invalid port ${String(port)}`, {\n hint: \"Use a TCP port between 1 and 65535.\",\n });\n }\n}\n"],"mappings":"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"}
@@ -1,46 +1,93 @@
1
- import { a as readZitadelConfig, n as hasZitadelSecret, o as readZitadelSecret, r as readDevelopmentIssuer, s as BaseCommand } from "../project-C3pSfbao.mjs";
1
+ import { c as checkLocalServerHealth, g as readRuntimeMetadata, p as localContainerName, t as BaseCommand, x as publicCliCommand, y as runtimeSummary } from "../oclif-CqkWBQ7i.mjs";
2
+ import { a as readZitadelConfig, n as hasZitadelSecret, o as readZitadelSecret, r as readDevelopmentIssuer, t as hasZitadelConfig } from "../project-B6YfSaZw.mjs";
3
+ import { s as inspectContainer } from "../docker-DrOBycgG.mjs";
2
4
  //#region src/commands/status.ts
3
5
  /**
4
- * `zitadel status` — summarize the local project state.
6
+ * `zitadel status` — summarize the local server and project state.
5
7
  *
6
- * Reads `zitadel.json` and its secret. A present config with a missing secret
7
- * is treated as an "orphaned" install (returned as skipped with recovery
8
- * commands) rather than an error, so status stays informational and safe to
9
- * run on partial or broken setups.
8
+ * This is intentionally informational: a missing `zitadel.json`, stopped
9
+ * local server, or orphaned config should be visible without making `status`
10
+ * itself fail.
10
11
  */
11
12
  var Status = class Status extends BaseCommand {
12
- static description = "Summarize the local project state.";
13
+ static description = "Summarize the local Zitadel server and project state.";
13
14
  async run() {
14
15
  const { flags } = await this.parse(Status);
15
- await this.toMeta(flags);
16
- const { cwd, source } = this.meta;
17
- const config = await readZitadelConfig(cwd);
18
- if (!await hasZitadelSecret(cwd)) return this.emit({
19
- status: "skipped",
20
- reason: "orphaned-config",
21
- data: {
22
- project_id: typeof config.project === "string" ? config.project : void 0,
23
- lifecycle: "orphaned-config",
24
- message: "zitadel.json exists but .zitadel/secret is missing."
25
- },
26
- nextCommands: ["zitadel setup --force", "zitadel doctor --fix"]
16
+ const runtime = await readRuntimeMetadata(flags.cwd ? String(flags.cwd) : process.cwd());
17
+ if (flags.server === "local") await this.toMeta(flags, {
18
+ resolveServer: false,
19
+ source: runtime?.server_url ?? "http://localhost:8080"
27
20
  });
28
- const secret = await readZitadelSecret(cwd);
21
+ else await this.toMeta(flags);
22
+ const { cwd } = this.meta;
23
+ const containerName = runtime?.container_name ?? localContainerName(cwd);
24
+ let docker;
25
+ let dockerError;
26
+ try {
27
+ docker = await inspectContainer(containerName);
28
+ } catch (error) {
29
+ dockerError = error instanceof Error ? error.message : String(error);
30
+ }
31
+ const healthy = runtime ? await checkLocalServerHealth(runtime.server_url) : false;
32
+ const serverLifecycle = runtime ? docker?.running && healthy ? "running" : docker?.exists ? "unhealthy" : "stopped" : "missing";
33
+ const project = await projectStatus(cwd);
34
+ const nextCommands = nextCommandsFor(serverLifecycle, project.lifecycle, this.meta.cliVersion);
35
+ const nextActions = nextActionsFor(project.lifecycle);
29
36
  return this.emit({
30
37
  status: "ok",
31
38
  data: {
32
- title: "Zitadel project detected.",
33
- project: {
34
- project_id: String(config.project ?? secret.project_id ?? ""),
35
- issuer: readDevelopmentIssuer(config)
39
+ title: "Zitadel status.",
40
+ server: {
41
+ lifecycle: serverLifecycle,
42
+ runtime: runtimeSummary(runtime),
43
+ docker: {
44
+ available: dockerError === void 0,
45
+ error: dockerError,
46
+ container_exists: docker?.exists ?? false,
47
+ container_running: docker?.running ?? false
48
+ },
49
+ health: {
50
+ healthy,
51
+ url: runtime?.server_url
52
+ }
36
53
  },
37
- server: source,
38
- next_actions: ["Run `zitadel doctor`.", "Run `zitadel apply` after config changes."],
39
- next_commands: ["zitadel doctor", "zitadel apply"]
54
+ project,
55
+ next_actions: nextActions,
56
+ next_commands: nextCommands
40
57
  }
41
58
  });
42
59
  }
43
60
  };
61
+ async function projectStatus(cwd) {
62
+ if (!await hasZitadelConfig(cwd)) return {
63
+ lifecycle: "not-configured",
64
+ message: "zitadel.json has not been created yet."
65
+ };
66
+ const config = await readZitadelConfig(cwd);
67
+ if (!await hasZitadelSecret(cwd)) return {
68
+ lifecycle: "orphaned-config",
69
+ project_id: typeof config.project === "string" ? config.project : void 0,
70
+ message: "zitadel.json exists but .zitadel/secret is missing."
71
+ };
72
+ const secret = await readZitadelSecret(cwd);
73
+ return {
74
+ lifecycle: "configured",
75
+ project_id: String(config.project ?? secret.project_id ?? ""),
76
+ issuer: readDevelopmentIssuer(config)
77
+ };
78
+ }
79
+ function nextActionsFor(projectLifecycle) {
80
+ if (projectLifecycle === "not-configured") return ["From your app directory, run setup; the CLI will detect the framework or ask in an empty directory."];
81
+ return [];
82
+ }
83
+ function nextCommandsFor(serverLifecycle, projectLifecycle, cliVersion) {
84
+ const commands = [];
85
+ if (serverLifecycle !== "running") commands.push(publicCliCommand("start", cliVersion));
86
+ if (projectLifecycle === "not-configured") commands.push(publicCliCommand("setup --server local", cliVersion));
87
+ else if (projectLifecycle === "orphaned-config") commands.push(publicCliCommand("setup --force", cliVersion), publicCliCommand("doctor --fix", cliVersion));
88
+ else commands.push(publicCliCommand("doctor", cliVersion), publicCliCommand("apply", cliVersion));
89
+ return commands;
90
+ }
44
91
  //#endregion
45
92
  export { Status as default };
46
93
 
@@ -1 +1 @@
1
- {"version":3,"file":"status.mjs","names":[],"sources":["../../src/commands/status.ts"],"sourcesContent":["import { BaseCommand, type JsonEnvelope } from \"../lib/oclif\";\nimport {\n hasZitadelSecret,\n readDevelopmentIssuer,\n readZitadelConfig,\n readZitadelSecret,\n} from \"../lib/project\";\n\n/**\n * `zitadel status` — summarize the local project state.\n *\n * Reads `zitadel.json` and its secret. A present config with a missing secret\n * is treated as an \"orphaned\" install (returned as skipped with recovery\n * commands) rather than an error, so status stays informational and safe to\n * run on partial or broken setups.\n */\nexport default class Status extends BaseCommand {\n static override description = \"Summarize the local project state.\";\n\n async run(): Promise<JsonEnvelope> {\n const { flags } = await this.parse(Status);\n await this.toMeta(flags);\n const { cwd, source } = this.meta;\n\n const config = await readZitadelConfig(cwd);\n\n if (!(await hasZitadelSecret(cwd))) {\n return this.emit({\n status: \"skipped\",\n reason: \"orphaned-config\",\n data: {\n project_id: typeof config.project === \"string\" ? config.project : undefined,\n lifecycle: \"orphaned-config\",\n message: \"zitadel.json exists but .zitadel/secret is missing.\",\n },\n nextCommands: [\"zitadel setup --force\", \"zitadel doctor --fix\"],\n });\n }\n\n const secret = await readZitadelSecret(cwd);\n return this.emit({\n status: \"ok\",\n data: {\n title: \"Zitadel project detected.\",\n project: {\n project_id: String(config.project ?? secret.project_id ?? \"\"),\n issuer: readDevelopmentIssuer(config),\n },\n server: source,\n next_actions: [\"Run `zitadel doctor`.\", \"Run `zitadel apply` after config changes.\"],\n next_commands: [\"zitadel doctor\", \"zitadel apply\"],\n },\n });\n }\n}\n"],"mappings":";;;;;;;;;;AAgBA,IAAqB,SAArB,MAAqB,eAAe,YAAY;CAC9C,OAAgB,cAAc;CAE9B,MAAM,MAA6B;EACjC,MAAM,EAAE,UAAU,MAAM,KAAK,MAAM,OAAO;AAC1C,QAAM,KAAK,OAAO,MAAM;EACxB,MAAM,EAAE,KAAK,WAAW,KAAK;EAE7B,MAAM,SAAS,MAAM,kBAAkB,IAAI;AAE3C,MAAI,CAAE,MAAM,iBAAiB,IAAI,CAC/B,QAAO,KAAK,KAAK;GACf,QAAQ;GACR,QAAQ;GACR,MAAM;IACJ,YAAY,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU,KAAA;IAClE,WAAW;IACX,SAAS;IACV;GACD,cAAc,CAAC,yBAAyB,uBAAuB;GAChE,CAAC;EAGJ,MAAM,SAAS,MAAM,kBAAkB,IAAI;AAC3C,SAAO,KAAK,KAAK;GACf,QAAQ;GACR,MAAM;IACJ,OAAO;IACP,SAAS;KACP,YAAY,OAAO,OAAO,WAAW,OAAO,cAAc,GAAG;KAC7D,QAAQ,sBAAsB,OAAO;KACtC;IACD,QAAQ;IACR,cAAc,CAAC,yBAAyB,4CAA4C;IACpF,eAAe,CAAC,kBAAkB,gBAAgB;IACnD;GACF,CAAC"}
1
+ {"version":3,"file":"status.mjs","names":[],"sources":["../../src/commands/status.ts"],"sourcesContent":["import { inspectContainer } from \"../lib/local-server/docker\";\nimport {\n DEFAULT_LOCAL_SERVER_URL,\n checkLocalServerHealth,\n localContainerName,\n readRuntimeMetadata,\n runtimeSummary,\n} from \"../lib/local-server/runtime\";\nimport { BaseCommand, type JsonEnvelope } from \"../lib/oclif\";\nimport {\n hasZitadelConfig,\n hasZitadelSecret,\n readDevelopmentIssuer,\n readZitadelConfig,\n readZitadelSecret,\n} from \"../lib/project\";\nimport { publicCliCommand } from \"../lib/public-cli\";\n\n/**\n * `zitadel status` — summarize the local server and project state.\n *\n * This is intentionally informational: a missing `zitadel.json`, stopped\n * local server, or orphaned config should be visible without making `status`\n * itself fail.\n */\nexport default class Status extends BaseCommand {\n static override description = \"Summarize the local Zitadel server and project state.\";\n\n async run(): Promise<JsonEnvelope> {\n const { flags } = await this.parse(Status);\n const runtime = await readRuntimeMetadata(flags.cwd ? String(flags.cwd) : process.cwd());\n if (flags.server === \"local\") {\n await this.toMeta(flags, {\n resolveServer: false,\n source: runtime?.server_url ?? DEFAULT_LOCAL_SERVER_URL,\n });\n } else {\n await this.toMeta(flags);\n }\n const { cwd } = this.meta;\n\n const containerName = runtime?.container_name ?? localContainerName(cwd);\n let docker: Awaited<ReturnType<typeof inspectContainer>> | undefined;\n let dockerError: string | undefined;\n try {\n docker = await inspectContainer(containerName);\n } catch (error) {\n dockerError = error instanceof Error ? error.message : String(error);\n }\n const healthy = runtime ? await checkLocalServerHealth(runtime.server_url) : false;\n const serverLifecycle = runtime\n ? docker?.running && healthy\n ? \"running\"\n : docker?.exists\n ? \"unhealthy\"\n : \"stopped\"\n : \"missing\";\n\n const project = await projectStatus(cwd);\n const nextCommands = nextCommandsFor(serverLifecycle, project.lifecycle, this.meta.cliVersion);\n const nextActions = nextActionsFor(project.lifecycle);\n\n return this.emit({\n status: \"ok\",\n data: {\n title: \"Zitadel status.\",\n server: {\n lifecycle: serverLifecycle,\n runtime: runtimeSummary(runtime),\n docker: {\n available: dockerError === undefined,\n error: dockerError,\n container_exists: docker?.exists ?? false,\n container_running: docker?.running ?? false,\n },\n health: {\n healthy,\n url: runtime?.server_url,\n },\n },\n project,\n next_actions: nextActions,\n next_commands: nextCommands,\n },\n });\n }\n}\n\ntype ProjectStatus =\n | {\n lifecycle: \"not-configured\";\n message: string;\n }\n | {\n lifecycle: \"orphaned-config\";\n project_id?: string;\n message: string;\n }\n | {\n lifecycle: \"configured\";\n project_id: string;\n issuer?: string;\n };\n\nasync function projectStatus(cwd: string): Promise<ProjectStatus> {\n if (!(await hasZitadelConfig(cwd))) {\n return {\n lifecycle: \"not-configured\",\n message: \"zitadel.json has not been created yet.\",\n };\n }\n\n const config = await readZitadelConfig(cwd);\n if (!(await hasZitadelSecret(cwd))) {\n return {\n lifecycle: \"orphaned-config\",\n project_id: typeof config.project === \"string\" ? config.project : undefined,\n message: \"zitadel.json exists but .zitadel/secret is missing.\",\n };\n }\n\n const secret = await readZitadelSecret(cwd);\n return {\n lifecycle: \"configured\",\n project_id: String(config.project ?? secret.project_id ?? \"\"),\n issuer: readDevelopmentIssuer(config),\n };\n}\n\nfunction nextActionsFor(projectLifecycle: ProjectStatus[\"lifecycle\"]): string[] {\n if (projectLifecycle === \"not-configured\") {\n return [\n \"From your app directory, run setup; the CLI will detect the framework or ask in an empty directory.\",\n ];\n }\n return [];\n}\n\nfunction nextCommandsFor(\n serverLifecycle: string,\n projectLifecycle: ProjectStatus[\"lifecycle\"],\n cliVersion: string,\n): string[] {\n const commands: string[] = [];\n if (serverLifecycle !== \"running\") {\n commands.push(publicCliCommand(\"start\", cliVersion));\n }\n if (projectLifecycle === \"not-configured\") {\n commands.push(publicCliCommand(\"setup --server local\", cliVersion));\n } else if (projectLifecycle === \"orphaned-config\") {\n commands.push(\n publicCliCommand(\"setup --force\", cliVersion),\n publicCliCommand(\"doctor --fix\", cliVersion),\n );\n } else {\n commands.push(publicCliCommand(\"doctor\", cliVersion), publicCliCommand(\"apply\", cliVersion));\n }\n return commands;\n}\n"],"mappings":";;;;;;;;;;;AAyBA,IAAqB,SAArB,MAAqB,eAAe,YAAY;CAC9C,OAAgB,cAAc;CAE9B,MAAM,MAA6B;EACjC,MAAM,EAAE,UAAU,MAAM,KAAK,MAAM,OAAO;EAC1C,MAAM,UAAU,MAAM,oBAAoB,MAAM,MAAM,OAAO,MAAM,IAAI,GAAG,QAAQ,KAAK,CAAC;AACxF,MAAI,MAAM,WAAW,QACnB,OAAM,KAAK,OAAO,OAAO;GACvB,eAAe;GACf,QAAQ,SAAS,cAAA;GAClB,CAAC;MAEF,OAAM,KAAK,OAAO,MAAM;EAE1B,MAAM,EAAE,QAAQ,KAAK;EAErB,MAAM,gBAAgB,SAAS,kBAAkB,mBAAmB,IAAI;EACxE,IAAI;EACJ,IAAI;AACJ,MAAI;AACF,YAAS,MAAM,iBAAiB,cAAc;WACvC,OAAO;AACd,iBAAc,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;;EAEtE,MAAM,UAAU,UAAU,MAAM,uBAAuB,QAAQ,WAAW,GAAG;EAC7E,MAAM,kBAAkB,UACpB,QAAQ,WAAW,UACjB,YACA,QAAQ,SACN,cACA,YACJ;EAEJ,MAAM,UAAU,MAAM,cAAc,IAAI;EACxC,MAAM,eAAe,gBAAgB,iBAAiB,QAAQ,WAAW,KAAK,KAAK,WAAW;EAC9F,MAAM,cAAc,eAAe,QAAQ,UAAU;AAErD,SAAO,KAAK,KAAK;GACf,QAAQ;GACR,MAAM;IACJ,OAAO;IACP,QAAQ;KACN,WAAW;KACX,SAAS,eAAe,QAAQ;KAChC,QAAQ;MACN,WAAW,gBAAgB,KAAA;MAC3B,OAAO;MACP,kBAAkB,QAAQ,UAAU;MACpC,mBAAmB,QAAQ,WAAW;MACvC;KACD,QAAQ;MACN;MACA,KAAK,SAAS;MACf;KACF;IACD;IACA,cAAc;IACd,eAAe;IAChB;GACF,CAAC;;;AAoBN,eAAe,cAAc,KAAqC;AAChE,KAAI,CAAE,MAAM,iBAAiB,IAAI,CAC/B,QAAO;EACL,WAAW;EACX,SAAS;EACV;CAGH,MAAM,SAAS,MAAM,kBAAkB,IAAI;AAC3C,KAAI,CAAE,MAAM,iBAAiB,IAAI,CAC/B,QAAO;EACL,WAAW;EACX,YAAY,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU,KAAA;EAClE,SAAS;EACV;CAGH,MAAM,SAAS,MAAM,kBAAkB,IAAI;AAC3C,QAAO;EACL,WAAW;EACX,YAAY,OAAO,OAAO,WAAW,OAAO,cAAc,GAAG;EAC7D,QAAQ,sBAAsB,OAAO;EACtC;;AAGH,SAAS,eAAe,kBAAwD;AAC9E,KAAI,qBAAqB,iBACvB,QAAO,CACL,sGACD;AAEH,QAAO,EAAE;;AAGX,SAAS,gBACP,iBACA,kBACA,YACU;CACV,MAAM,WAAqB,EAAE;AAC7B,KAAI,oBAAoB,UACtB,UAAS,KAAK,iBAAiB,SAAS,WAAW,CAAC;AAEtD,KAAI,qBAAqB,iBACvB,UAAS,KAAK,iBAAiB,wBAAwB,WAAW,CAAC;UAC1D,qBAAqB,kBAC9B,UAAS,KACP,iBAAiB,iBAAiB,WAAW,EAC7C,iBAAiB,gBAAgB,WAAW,CAC7C;KAED,UAAS,KAAK,iBAAiB,UAAU,WAAW,EAAE,iBAAiB,SAAS,WAAW,CAAC;AAE9F,QAAO"}
@@ -0,0 +1,43 @@
1
+ import { g as readRuntimeMetadata, p as localContainerName, t as BaseCommand, x as publicCliCommand } from "../oclif-CqkWBQ7i.mjs";
2
+ import { u as stopAndRemoveContainer } from "../docker-DrOBycgG.mjs";
3
+ //#region src/commands/stop.ts
4
+ var Stop = class Stop extends BaseCommand {
5
+ static description = "Stop the local Zitadel server.";
6
+ async run() {
7
+ const { flags } = await this.parse(Stop);
8
+ const runtime = await readRuntimeMetadata(flags.cwd ? String(flags.cwd) : process.cwd());
9
+ await this.toMeta(flags, {
10
+ resolveServer: false,
11
+ source: runtime?.server_url ?? "http://localhost:8080"
12
+ });
13
+ const containerName = runtime?.container_name ?? localContainerName(this.meta.cwd);
14
+ if (this.meta.dryRun) return this.emit({
15
+ status: "ok",
16
+ data: {
17
+ title: "Local Zitadel server stop plan.",
18
+ runtime: {
19
+ container_name: containerName,
20
+ data_preserved: true,
21
+ data_dir: runtime?.data_dir
22
+ },
23
+ next_commands: [publicCliCommand("stop", this.meta.cliVersion)]
24
+ }
25
+ });
26
+ await stopAndRemoveContainer(containerName);
27
+ return this.emit({
28
+ status: "ok",
29
+ data: {
30
+ title: "Local Zitadel server stopped.",
31
+ runtime: {
32
+ container_name: containerName,
33
+ data_preserved: true,
34
+ data_dir: runtime?.data_dir
35
+ }
36
+ }
37
+ });
38
+ }
39
+ };
40
+ //#endregion
41
+ export { Stop as default };
42
+
43
+ //# sourceMappingURL=stop.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop.mjs","names":[],"sources":["../../src/commands/stop.ts"],"sourcesContent":["import { stopAndRemoveContainer } from \"../lib/local-server/docker\";\nimport {\n DEFAULT_LOCAL_SERVER_URL,\n localContainerName,\n readRuntimeMetadata,\n} from \"../lib/local-server/runtime\";\nimport { BaseCommand, type JsonEnvelope } from \"../lib/oclif\";\nimport { publicCliCommand } from \"../lib/public-cli\";\n\nexport default class Stop extends BaseCommand {\n static override description = \"Stop the local Zitadel server.\";\n\n async run(): Promise<JsonEnvelope> {\n const { flags } = await this.parse(Stop);\n const runtime = await readRuntimeMetadata(flags.cwd ? String(flags.cwd) : process.cwd());\n await this.toMeta(flags, {\n resolveServer: false,\n source: runtime?.server_url ?? DEFAULT_LOCAL_SERVER_URL,\n });\n\n const containerName = runtime?.container_name ?? localContainerName(this.meta.cwd);\n if (this.meta.dryRun) {\n return this.emit({\n status: \"ok\",\n data: {\n title: \"Local Zitadel server stop plan.\",\n runtime: {\n container_name: containerName,\n data_preserved: true,\n data_dir: runtime?.data_dir,\n },\n next_commands: [publicCliCommand(\"stop\", this.meta.cliVersion)],\n },\n });\n }\n\n await stopAndRemoveContainer(containerName);\n\n return this.emit({\n status: \"ok\",\n data: {\n title: \"Local Zitadel server stopped.\",\n runtime: {\n container_name: containerName,\n data_preserved: true,\n data_dir: runtime?.data_dir,\n },\n },\n });\n }\n}\n"],"mappings":";;;AASA,IAAqB,OAArB,MAAqB,aAAa,YAAY;CAC5C,OAAgB,cAAc;CAE9B,MAAM,MAA6B;EACjC,MAAM,EAAE,UAAU,MAAM,KAAK,MAAM,KAAK;EACxC,MAAM,UAAU,MAAM,oBAAoB,MAAM,MAAM,OAAO,MAAM,IAAI,GAAG,QAAQ,KAAK,CAAC;AACxF,QAAM,KAAK,OAAO,OAAO;GACvB,eAAe;GACf,QAAQ,SAAS,cAAA;GAClB,CAAC;EAEF,MAAM,gBAAgB,SAAS,kBAAkB,mBAAmB,KAAK,KAAK,IAAI;AAClF,MAAI,KAAK,KAAK,OACZ,QAAO,KAAK,KAAK;GACf,QAAQ;GACR,MAAM;IACJ,OAAO;IACP,SAAS;KACP,gBAAgB;KAChB,gBAAgB;KAChB,UAAU,SAAS;KACpB;IACD,eAAe,CAAC,iBAAiB,QAAQ,KAAK,KAAK,WAAW,CAAC;IAChE;GACF,CAAC;AAGJ,QAAM,uBAAuB,cAAc;AAE3C,SAAO,KAAK,KAAK;GACf,QAAQ;GACR,MAAM;IACJ,OAAO;IACP,SAAS;KACP,gBAAgB;KAChB,gBAAgB;KAChB,UAAU,SAAS;KACpB;IACF;GACF,CAAC"}
@@ -0,0 +1,210 @@
1
+ import { E as ZitadelError, i as CONTAINER_HTTP_PORT, r as CONTAINER_DATA_DIR } from "./oclif-CqkWBQ7i.mjs";
2
+ import { spawn } from "node:child_process";
3
+ //#region src/lib/local-server/docker.ts
4
+ function dockerRunArgs(spec) {
5
+ const args = [
6
+ "run",
7
+ "--detach",
8
+ "--name",
9
+ spec.containerName,
10
+ "--publish",
11
+ `127.0.0.1:${spec.port}:${CONTAINER_HTTP_PORT}`,
12
+ "--volume",
13
+ `${spec.dataDir}:${CONTAINER_DATA_DIR}`,
14
+ "--env",
15
+ `NEXTGEN_SERVER_ADDRESS=:${CONTAINER_HTTP_PORT}`,
16
+ "--env",
17
+ `NEXTGEN_SERVER_DATA_DIR=${CONTAINER_DATA_DIR}`
18
+ ];
19
+ if (spec.identity) args.push("--volume", `${spec.identity.passwdFile}:/etc/passwd:ro`, "--volume", `${spec.identity.groupFile}:/etc/group:ro`, "--user", `${spec.identity.uid}:${spec.identity.gid}`);
20
+ args.push(spec.image);
21
+ return args;
22
+ }
23
+ async function runDocker(args) {
24
+ return new Promise((resolve, reject) => {
25
+ const child = spawn("docker", args, {
26
+ stdio: [
27
+ "ignore",
28
+ "pipe",
29
+ "pipe"
30
+ ],
31
+ env: process.env
32
+ });
33
+ let stdout = "";
34
+ let stderr = "";
35
+ child.stdout?.setEncoding("utf8");
36
+ child.stderr?.setEncoding("utf8");
37
+ child.stdout?.on("data", (chunk) => {
38
+ stdout += chunk;
39
+ });
40
+ child.stderr?.on("data", (chunk) => {
41
+ stderr += chunk;
42
+ });
43
+ child.on("error", reject);
44
+ child.on("close", (code) => {
45
+ resolve({
46
+ status: code ?? 1,
47
+ stdout,
48
+ stderr
49
+ });
50
+ });
51
+ });
52
+ }
53
+ async function streamDocker(args) {
54
+ await new Promise((resolve, reject) => {
55
+ const child = spawn("docker", args, {
56
+ stdio: "inherit",
57
+ env: process.env
58
+ });
59
+ child.on("error", reject);
60
+ child.on("close", (code) => {
61
+ if (code === 0) resolve();
62
+ else reject(/* @__PURE__ */ new Error(`docker ${args.join(" ")} exited with status ${code ?? 1}`));
63
+ });
64
+ });
65
+ }
66
+ async function dockerAvailable() {
67
+ return runDocker([
68
+ "version",
69
+ "--format",
70
+ "{{.Server.Version}}"
71
+ ]);
72
+ }
73
+ async function pullImage(image) {
74
+ await requireDocker([
75
+ "pull",
76
+ "--quiet",
77
+ image
78
+ ], `Pull Docker image ${image}`);
79
+ }
80
+ async function imageExists(image) {
81
+ let result;
82
+ const args = [
83
+ "image",
84
+ "inspect",
85
+ image
86
+ ];
87
+ try {
88
+ result = await runDocker(args);
89
+ } catch (error) {
90
+ throw dockerError(`Inspect Docker image ${image}`, args, error);
91
+ }
92
+ return result.status === 0;
93
+ }
94
+ async function imageAvailable(image) {
95
+ if (await imageExists(image)) return "local";
96
+ const args = [
97
+ "manifest",
98
+ "inspect",
99
+ image
100
+ ];
101
+ let result;
102
+ try {
103
+ result = await runDocker(args);
104
+ } catch (error) {
105
+ throw dockerError(`Inspect Docker image ${image}`, args, error);
106
+ }
107
+ if (result.status === 0) return "remote";
108
+ throw dockerError(`Inspect Docker image ${image}`, args, result);
109
+ }
110
+ async function ensureImage(image) {
111
+ if (await imageExists(image)) return "local";
112
+ await pullImage(image);
113
+ return "pulled";
114
+ }
115
+ async function inspectContainer(containerName) {
116
+ const result = await runDocker([
117
+ "inspect",
118
+ "--format",
119
+ "{{.Id}} {{.State.Running}} {{.Config.Image}}",
120
+ containerName
121
+ ]);
122
+ if (result.status !== 0) return {
123
+ exists: false,
124
+ running: false
125
+ };
126
+ const [id, running, ...imageParts] = result.stdout.trim().split(/\s+/);
127
+ return {
128
+ exists: true,
129
+ running: running === "true",
130
+ id,
131
+ image: imageParts.join(" ")
132
+ };
133
+ }
134
+ async function startContainer(spec) {
135
+ return (await requireDocker(dockerRunArgs(spec), "Start local Zitadel container")).stdout.trim();
136
+ }
137
+ async function stopAndRemoveContainer(containerName) {
138
+ const inspect = await inspectContainer(containerName);
139
+ if (!inspect.exists) return;
140
+ if (inspect.running) await requireDocker(["stop", containerName], `Stop ${containerName}`);
141
+ await requireDocker(["rm", containerName], `Remove ${containerName}`);
142
+ }
143
+ async function containerLogs(containerName, tail) {
144
+ return (await requireDocker([
145
+ "logs",
146
+ "--tail",
147
+ String(tail),
148
+ containerName
149
+ ], "Read logs")).stdout;
150
+ }
151
+ async function followContainerLogs(containerName, tail) {
152
+ await streamDocker([
153
+ "logs",
154
+ "--tail",
155
+ String(tail),
156
+ "--follow",
157
+ containerName
158
+ ]);
159
+ }
160
+ function currentUser() {
161
+ const getuid = process.getuid;
162
+ const getgid = process.getgid;
163
+ if (typeof getuid !== "function") return {};
164
+ const uid = getuid();
165
+ return {
166
+ uid,
167
+ gid: typeof getgid === "function" ? getgid() : uid
168
+ };
169
+ }
170
+ function metadataFromStart(input) {
171
+ return {
172
+ schema_version: 1,
173
+ container_name: input.containerName,
174
+ container_id: input.containerId,
175
+ image: input.image,
176
+ port: input.port,
177
+ server_url: input.serverUrl,
178
+ data_dir: input.cwdDataDir,
179
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
180
+ cli_version: input.cliVersion
181
+ };
182
+ }
183
+ async function requireDocker(args, action) {
184
+ let result;
185
+ try {
186
+ result = await runDocker(args);
187
+ } catch (error) {
188
+ throw dockerError(action, args, error);
189
+ }
190
+ if (result.status !== 0) throw dockerError(action, args, result);
191
+ return result;
192
+ }
193
+ function dockerError(action, args, cause) {
194
+ const details = cause && typeof cause === "object" && "stderr" in cause ? {
195
+ command: ["docker", ...args],
196
+ stderr: String(cause.stderr)
197
+ } : {
198
+ command: ["docker", ...args],
199
+ cause
200
+ };
201
+ return new ZitadelError("E_VALIDATION", `${action} failed`, {
202
+ hint: "Check that Docker is installed, running, and reachable from this shell.",
203
+ nextCommands: ["zitadel doctor"],
204
+ details
205
+ });
206
+ }
207
+ //#endregion
208
+ export { followContainerLogs as a, metadataFromStart as c, ensureImage as i, startContainer as l, currentUser as n, imageAvailable as o, dockerAvailable as r, inspectContainer as s, containerLogs as t, stopAndRemoveContainer as u };
209
+
210
+ //# sourceMappingURL=docker-DrOBycgG.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker-DrOBycgG.mjs","names":[],"sources":["../src/lib/local-server/docker.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\n\nimport { ZitadelError } from \"../errors\";\nimport {\n CONTAINER_DATA_DIR,\n CONTAINER_HTTP_PORT,\n type ContainerIdentity,\n type RuntimeMetadata,\n} from \"./runtime\";\n\nexport type DockerResult = {\n status: number;\n stdout: string;\n stderr: string;\n};\n\nexport type DockerRunSpec = {\n containerName: string;\n image: string;\n port: number;\n dataDir: string;\n identity?: ContainerIdentity;\n};\n\nexport function dockerRunArgs(spec: DockerRunSpec): string[] {\n const args = [\n \"run\",\n \"--detach\",\n \"--name\",\n spec.containerName,\n \"--publish\",\n `127.0.0.1:${spec.port}:${CONTAINER_HTTP_PORT}`,\n \"--volume\",\n `${spec.dataDir}:${CONTAINER_DATA_DIR}`,\n \"--env\",\n `NEXTGEN_SERVER_ADDRESS=:${CONTAINER_HTTP_PORT}`,\n \"--env\",\n `NEXTGEN_SERVER_DATA_DIR=${CONTAINER_DATA_DIR}`,\n ];\n\n if (spec.identity) {\n args.push(\n \"--volume\",\n `${spec.identity.passwdFile}:/etc/passwd:ro`,\n \"--volume\",\n `${spec.identity.groupFile}:/etc/group:ro`,\n \"--user\",\n `${spec.identity.uid}:${spec.identity.gid}`,\n );\n }\n\n args.push(spec.image);\n return args;\n}\n\nexport async function runDocker(args: string[]): Promise<DockerResult> {\n return new Promise((resolve, reject) => {\n const child = spawn(\"docker\", args, {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: process.env,\n });\n let stdout = \"\";\n let stderr = \"\";\n child.stdout?.setEncoding(\"utf8\");\n child.stderr?.setEncoding(\"utf8\");\n child.stdout?.on(\"data\", (chunk: string) => {\n stdout += chunk;\n });\n child.stderr?.on(\"data\", (chunk: string) => {\n stderr += chunk;\n });\n child.on(\"error\", reject);\n child.on(\"close\", (code) => {\n resolve({ status: code ?? 1, stdout, stderr });\n });\n });\n}\n\nexport async function streamDocker(args: string[]): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const child = spawn(\"docker\", args, {\n stdio: \"inherit\",\n env: process.env,\n });\n child.on(\"error\", reject);\n child.on(\"close\", (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`docker ${args.join(\" \")} exited with status ${code ?? 1}`));\n }\n });\n });\n}\n\nexport async function dockerAvailable(): Promise<DockerResult> {\n return runDocker([\"version\", \"--format\", \"{{.Server.Version}}\"]);\n}\n\nexport async function pullImage(image: string): Promise<void> {\n await requireDocker([\"pull\", \"--quiet\", image], `Pull Docker image ${image}`);\n}\n\nexport async function imageExists(image: string): Promise<boolean> {\n let result: DockerResult;\n const args = [\"image\", \"inspect\", image];\n try {\n result = await runDocker(args);\n } catch (error) {\n throw dockerError(`Inspect Docker image ${image}`, args, error);\n }\n return result.status === 0;\n}\n\nexport async function imageAvailable(image: string): Promise<\"local\" | \"remote\"> {\n if (await imageExists(image)) {\n return \"local\";\n }\n\n const args = [\"manifest\", \"inspect\", image];\n let result: DockerResult;\n try {\n result = await runDocker(args);\n } catch (error) {\n throw dockerError(`Inspect Docker image ${image}`, args, error);\n }\n if (result.status === 0) {\n return \"remote\";\n }\n throw dockerError(`Inspect Docker image ${image}`, args, result);\n}\n\nexport async function ensureImage(image: string): Promise<\"local\" | \"pulled\"> {\n if (await imageExists(image)) {\n return \"local\";\n }\n await pullImage(image);\n return \"pulled\";\n}\n\nexport async function inspectContainer(containerName: string): Promise<{\n exists: boolean;\n running: boolean;\n id?: string;\n image?: string;\n}> {\n const result = await runDocker([\n \"inspect\",\n \"--format\",\n \"{{.Id}} {{.State.Running}} {{.Config.Image}}\",\n containerName,\n ]);\n if (result.status !== 0) {\n return { exists: false, running: false };\n }\n const [id, running, ...imageParts] = result.stdout.trim().split(/\\s+/);\n return { exists: true, running: running === \"true\", id, image: imageParts.join(\" \") };\n}\n\nexport async function startContainer(spec: DockerRunSpec): Promise<string> {\n const args = dockerRunArgs(spec);\n const result = await requireDocker(args, \"Start local Zitadel container\");\n return result.stdout.trim();\n}\n\nexport async function stopAndRemoveContainer(containerName: string): Promise<void> {\n const inspect = await inspectContainer(containerName);\n if (!inspect.exists) {\n return;\n }\n if (inspect.running) {\n await requireDocker([\"stop\", containerName], `Stop ${containerName}`);\n }\n await requireDocker([\"rm\", containerName], `Remove ${containerName}`);\n}\n\nexport async function containerLogs(containerName: string, tail: number): Promise<string> {\n const result = await requireDocker([\"logs\", \"--tail\", String(tail), containerName], \"Read logs\");\n return result.stdout;\n}\n\nexport async function followContainerLogs(containerName: string, tail: number): Promise<void> {\n await streamDocker([\"logs\", \"--tail\", String(tail), \"--follow\", containerName]);\n}\n\nexport function currentUser(): { uid?: number; gid?: number } {\n const getuid = process.getuid;\n const getgid = process.getgid;\n if (typeof getuid !== \"function\") {\n return {};\n }\n const uid = getuid();\n const gid = typeof getgid === \"function\" ? getgid() : uid;\n return { uid, gid };\n}\n\nexport function metadataFromStart(input: {\n cwdDataDir: string;\n cliVersion: string;\n containerName: string;\n containerId: string;\n image: string;\n port: number;\n serverUrl: string;\n}): RuntimeMetadata {\n return {\n schema_version: 1,\n container_name: input.containerName,\n container_id: input.containerId,\n image: input.image,\n port: input.port,\n server_url: input.serverUrl,\n data_dir: input.cwdDataDir,\n created_at: new Date().toISOString(),\n cli_version: input.cliVersion,\n };\n}\n\nexport async function requireDocker(args: string[], action: string): Promise<DockerResult> {\n let result: DockerResult;\n try {\n result = await runDocker(args);\n } catch (error) {\n throw dockerError(action, args, error);\n }\n if (result.status !== 0) {\n throw dockerError(action, args, result);\n }\n return result;\n}\n\nfunction dockerError(action: string, args: string[], cause: unknown): ZitadelError {\n const details =\n cause && typeof cause === \"object\" && \"stderr\" in cause\n ? { command: [\"docker\", ...args], stderr: String((cause as { stderr?: unknown }).stderr) }\n : { command: [\"docker\", ...args], cause };\n return new ZitadelError(\"E_VALIDATION\", `${action} failed`, {\n hint: \"Check that Docker is installed, running, and reachable from this shell.\",\n nextCommands: [\"zitadel doctor\"],\n details,\n });\n}\n"],"mappings":"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"}