hatchkit 0.1.37 → 0.1.39

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.
@@ -1 +1 @@
1
- {"version":3,"file":"coolify.d.ts","sourceRoot":"","sources":["../../src/deploy/coolify.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,MAAM,WAAW,sBAAsB;IACrC;;sCAEkC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;kEAE8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;uDAEmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC;;wDAEoD;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB;;gDAE4C;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB;;0EAEsE;IACtE,cAAc,EAAE,OAAO,CAAC;IACxB;;yCAEqC;IACrC,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;oDAEoD;AACpD,wBAAsB,eAAe,CACnC,MAAM,EAAE,aAAa,EACrB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,qBAAqB,CAAC,CA+IhC"}
1
+ {"version":3,"file":"coolify.d.ts","sourceRoot":"","sources":["../../src/deploy/coolify.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,MAAM,WAAW,sBAAsB;IACrC;;sCAEkC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;kEAE8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;uDAEmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC;;wDAEoD;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB;;gDAE4C;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB;;0EAEsE;IACtE,cAAc,EAAE,OAAO,CAAC;IACxB;;yCAEqC;IACrC,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;oDAEoD;AACpD,wBAAsB,eAAe,CACnC,MAAM,EAAE,aAAa,EACrB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,qBAAqB,CAAC,CA4KhC"}
@@ -65,16 +65,23 @@ export async function runCoolifySetup(config, options = {}) {
65
65
  projectCreated = true;
66
66
  console.log(chalk.green(` ✓ Project created: ${config.name} (${projectUuid})`));
67
67
  }
68
- // Domain routing: split across the two public services in the starter's
69
- // compose file (`server` and `client`). Coolify's dockercompose build
70
- // pack rejects a flat `domains` field (422 — "Use docker_compose_domains
71
- // instead to set domains for individual services") because routing has
72
- // to be per-service. The starter ships:
73
- // · client : Next.js (static or Node) — frontend hostname only
74
- // · server : Express API + WebSocket — every API/WS host
75
- // Traefik routes each domain to the matching service inside the compose
76
- // network; the app code itself only needs to handle the path/host
77
- // dispatch within `server`.
68
+ // Domain routing surface-aware. Coolify's dockercompose build pack
69
+ // rejects a flat `domains` field (422 "Use docker_compose_domains
70
+ // instead …") because routing is per-service.
71
+ //
72
+ // · both — `client` gets the bare hostname; `server` gets the
73
+ // api subdomain + the path-based API/WS hosts.
74
+ // · server-only no client service in the pruned compose, so the
75
+ // bare hostname AND every API/WS host all point at
76
+ // `server`. Browsers hitting `<domain>` reach the
77
+ // Express app directly (which can still serve a 200
78
+ // health page or redirect to the api host).
79
+ // · client-only — only the `client` service exists; nothing public
80
+ // about the API is needed. Currently unreachable
81
+ // from `hatchkit create` (the scaffold step throws
82
+ // before we get here) but the branch is wired so
83
+ // `hatchkit adopt`-driven client-only callers and a
84
+ // future create-side implementation share one path.
78
85
  const apiDomain = `api.${config.domain}`;
79
86
  const frontendDomain = `https://${config.domain}`;
80
87
  const backendDomains = [
@@ -83,17 +90,29 @@ export async function runCoolifySetup(config, options = {}) {
83
90
  `https://${config.domain}/api/ws`,
84
91
  `https://${apiDomain}/ws`,
85
92
  ];
86
- // Coolify's API takes a flat array of `{ name, domain }` entries, one
87
- // per (service, hostname) pair. Multi-domain services (the server here)
88
- // get one entry per domain rather than a comma-joined string — easier
89
- // for Coolify's per-domain routing rules.
90
- const dockerComposeDomains = [
91
- { name: "client", domain: frontendDomain },
92
- ...backendDomains.map((domain) => ({ name: "server", domain })),
93
- ];
93
+ const surfaces = config.surfaces ?? "both";
94
+ const dockerComposeDomains = surfaces === "client-only"
95
+ ? [{ name: "client", domain: frontendDomain }]
96
+ : surfaces === "server-only"
97
+ ? [
98
+ { name: "server", domain: frontendDomain },
99
+ ...backendDomains.map((domain) => ({ name: "server", domain })),
100
+ ]
101
+ : [
102
+ { name: "client", domain: frontendDomain },
103
+ ...backendDomains.map((domain) => ({ name: "server", domain })),
104
+ ];
94
105
  console.log(chalk.dim(" Domain routing:"));
95
- console.log(chalk.dim(` Frontend (client): ${frontendDomain}`));
96
- console.log(chalk.dim(` Backend (server): ${backendDomains.join(", ")}`));
106
+ if (surfaces === "client-only") {
107
+ console.log(chalk.dim(` Frontend (client): ${frontendDomain}`));
108
+ }
109
+ else if (surfaces === "server-only") {
110
+ console.log(chalk.dim(` All hosts → server: ${[frontendDomain, ...backendDomains].join(", ")}`));
111
+ }
112
+ else {
113
+ console.log(chalk.dim(` Frontend (client): ${frontendDomain}`));
114
+ console.log(chalk.dim(` Backend (server): ${backendDomains.join(", ")}`));
115
+ }
97
116
  // Application: reuse-by-name. `findApplicationByName` matches across
98
117
  // every project the user can see; first hit wins. Within a single
99
118
  // hatchkit-managed Coolify install, project names are unique enough
@@ -153,11 +172,17 @@ export async function runCoolifySetup(config, options = {}) {
153
172
  // .env.production and is decrypted at runtime via the dotenvx
154
173
  // private key that `hatchkit keys push` puts on Coolify. That keeps
155
174
  // prod secrets out of Coolify's UI.
156
- const envs = {
157
- NODE_ENV: "production",
158
- PORT: String(options.serverPort ?? 3000),
159
- FRONTEND_URL: `https://${config.domain}`,
160
- };
175
+ //
176
+ // Client-only scaffolds get only NODE_ENV — there's no server to
177
+ // honour PORT (the Next.js standalone server already binds 3000) and
178
+ // FRONTEND_URL is meaningless without a CORS-checking backend.
179
+ const envs = surfaces === "client-only"
180
+ ? { NODE_ENV: "production" }
181
+ : {
182
+ NODE_ENV: "production",
183
+ PORT: String(options.serverPort ?? 3000),
184
+ FRONTEND_URL: `https://${config.domain}`,
185
+ };
161
186
  await api.setAppEnv(appUuid, envs);
162
187
  console.log(chalk.green(` ✓ Set ${Object.keys(envs).length} env vars on application (${Object.keys(envs).join(", ")})`));
163
188
  console.log(chalk.green("\n ✓ Coolify app stack created"));
@@ -1 +1 @@
1
- {"version":3,"file":"coolify.js","sourceRoot":"","sources":["../../src/deploy/coolify.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"coolify.js","sourceRoot":"","sources":["../../src/deploy/coolify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ interface RegenArgs {
2
+ /** Project directory — defaults to cwd. The manifest must live here. */
3
+ projectDir: string;
4
+ /** Repo root for the hatchkit checkout (where the infra/ tree is). */
5
+ monorepoRoot: string;
6
+ /** Show the diff but don't write. */
7
+ dryRun: boolean;
8
+ }
9
+ export declare function runRegenInfraCli(args: string[], monorepoRoot: string): Promise<void>;
10
+ export declare function runRegenInfra(opts: RegenArgs): Promise<void>;
11
+ export {};
12
+ //# sourceMappingURL=regen-infra.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regen-infra.d.ts","sourceRoot":"","sources":["../../src/deploy/regen-infra.ts"],"names":[],"mappings":"AA8BA,UAAU,SAAS;IACjB,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,YAAY,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK1F;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAgGlE"}
@@ -0,0 +1,194 @@
1
+ /*
2
+ * `hatchkit regen-infra` — regenerate Terraform tfvars + Coolify stack
3
+ * .env for a scaffolded project, in place.
4
+ *
5
+ * Why this exists: `scaffoldInfra` runs once during `create` / `adopt`
6
+ * and bakes the project's choices into static files under
7
+ * `infra/terraform/stacks/.../<name>.tfvars` and `infra/stacks/<name>.env`.
8
+ * When the CLI's tfvars-generation logic changes (e.g. dropping the
9
+ * `api.<sub>` subdomain for client-only surfaces, or flipping
10
+ * `MONGO_ENABLED` based on the surface), existing projects keep their
11
+ * old files until someone re-runs scaffoldInfra. This command does
12
+ * exactly that — re-render from the manifest, preserve the infra-only
13
+ * fields the manifest doesn't carry (target_ipv4/v6 for dns-only,
14
+ * serverType / serverLocation for new-server), diff against what's on
15
+ * disk, and write the new files.
16
+ *
17
+ * Intentionally does NOT run `terraform apply` or touch Coolify. The
18
+ * user runs `terraform apply -var-file=<name>.tfvars` themselves once
19
+ * they've reviewed the plan.
20
+ */
21
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
22
+ import { basename, dirname, join, resolve } from "node:path";
23
+ import chalk from "chalk";
24
+ import { getConfig } from "../config.js";
25
+ import { generateCoolifyEnv, generateTfvars, resolveStackDir } from "../scaffold/infra.js";
26
+ import { readManifest } from "../scaffold/manifest.js";
27
+ import { parseDomain } from "../utils/validate.js";
28
+ export async function runRegenInfraCli(args, monorepoRoot) {
29
+ const dryRun = args.includes("--dry-run");
30
+ const dirFlag = args.findIndex((a) => a === "--dir");
31
+ const projectDir = resolve(dirFlag >= 0 ? (args[dirFlag + 1] ?? ".") : ".");
32
+ await runRegenInfra({ projectDir, monorepoRoot, dryRun });
33
+ }
34
+ export async function runRegenInfra(opts) {
35
+ const { projectDir, monorepoRoot, dryRun } = opts;
36
+ const manifest = readManifest(projectDir);
37
+ if (!manifest) {
38
+ throw new Error(`No .hatchkit.json in ${projectDir}. Run from inside a scaffolded project, or pass --dir <project-dir>.`);
39
+ }
40
+ // Locate the existing tfvars file. We try the same three stack dirs
41
+ // `resolveStackDir` knows about and pick the first hit — matches what
42
+ // `rename-domain.ts` does.
43
+ const candidatePaths = [
44
+ join(monorepoRoot, "infra", "terraform", "stacks", "node-realtime", `${manifest.name}.tfvars`),
45
+ join(monorepoRoot, "infra", "terraform", "stacks", "dns-only-cloudflare", `${manifest.name}.tfvars`),
46
+ join(monorepoRoot, "infra", "terraform", "stacks", "dns-only-inwx", `${manifest.name}.tfvars`),
47
+ ];
48
+ const existingTfvarsPath = candidatePaths.find((p) => existsSync(p));
49
+ // Reconstruct the bits of ProjectConfig the tfvars/coolify-env
50
+ // generators care about. Manifest carries the safe public-facing
51
+ // fields; everything infra-only (server coords, IPs, S3 creds) we
52
+ // either pull from the existing tfvars (when present) or accept as
53
+ // empty (terraform plan will fail loudly enough if a required value
54
+ // is missing).
55
+ const config = configFromManifestAndTfvars(manifest, existingTfvarsPath);
56
+ const newTfvars = generateTfvars(config);
57
+ const newCoolifyEnv = generateCoolifyEnv(config, {});
58
+ // Existing-content reads — null when the file doesn't yet exist so
59
+ // the diff shows the file as new.
60
+ const oldTfvars = existingTfvarsPath ? readFileSync(existingTfvarsPath, "utf-8") : "";
61
+ const coolifyEnvPath = join(monorepoRoot, "infra", "stacks", `${manifest.name}.env`);
62
+ const oldCoolifyEnv = existsSync(coolifyEnvPath) ? readFileSync(coolifyEnvPath, "utf-8") : "";
63
+ // Decide where the new tfvars should land — same dir as the existing
64
+ // file when we found one, else fall back to `resolveStackDir` so a
65
+ // fresh regen still produces a valid file. resolveStackDir resolves
66
+ // paths relative to the `infra/` root, not the monorepo root, so we
67
+ // join the prefix ourselves.
68
+ let tfvarsTargetPath = existingTfvarsPath;
69
+ if (!tfvarsTargetPath && newTfvars) {
70
+ const cfgDnsProvider = inferDnsProviderFromConfig();
71
+ const stackDir = resolveStackDir(join(monorepoRoot, "infra"), config.deployTarget, cfgDnsProvider);
72
+ if (stackDir)
73
+ tfvarsTargetPath = join(stackDir, `${manifest.name}.tfvars`);
74
+ }
75
+ console.log(chalk.bold(`\n ── regen-infra: ${manifest.name} ─────────────────────────`));
76
+ console.log(chalk.dim(` domain=${manifest.domain} surfaces=${manifest.surfaces ?? "both"} deploy=${manifest.deployTarget}`));
77
+ let touched = 0;
78
+ touched += renderFileChange("tfvars", tfvarsTargetPath, oldTfvars, newTfvars, dryRun);
79
+ touched += renderFileChange("coolify .env", coolifyEnvPath, oldCoolifyEnv, newCoolifyEnv, dryRun);
80
+ if (touched === 0) {
81
+ console.log(chalk.green("\n ✓ Already up to date — no changes."));
82
+ return;
83
+ }
84
+ if (dryRun) {
85
+ console.log(chalk.yellow(`\n [dry-run] ${touched} file(s) would be rewritten.`));
86
+ console.log(chalk.dim(" Re-run without --dry-run to apply."));
87
+ return;
88
+ }
89
+ console.log(chalk.green(`\n ✓ Regenerated ${touched} file(s).`));
90
+ if (tfvarsTargetPath && newTfvars && oldTfvars !== newTfvars) {
91
+ const stackDir = dirname(tfvarsTargetPath);
92
+ console.log(chalk.yellow(`\n Next: terraform -chdir=${stackDir} plan -var-file=${basename(tfvarsTargetPath)}`));
93
+ console.log(chalk.dim(` terraform -chdir=${stackDir} apply -var-file=${basename(tfvarsTargetPath)}`));
94
+ }
95
+ }
96
+ function renderFileChange(label, path, oldContent, newContent, dryRun) {
97
+ if (!path) {
98
+ console.log(chalk.dim(` ${label}: no target path resolved (manual DNS?) — skipped`));
99
+ return 0;
100
+ }
101
+ if (oldContent === newContent) {
102
+ console.log(chalk.dim(` ${label}: unchanged (${path})`));
103
+ return 0;
104
+ }
105
+ console.log(chalk.bold(`\n ${label}: ${chalk.cyan(path)}`));
106
+ printUnifiedDiff(oldContent, newContent);
107
+ if (!dryRun)
108
+ writeFileSync(path, newContent, "utf-8");
109
+ return 1;
110
+ }
111
+ /** Print a line-level diff between two strings using an LCS table — so
112
+ * removing one line in the middle doesn't make every subsequent line
113
+ * look changed. Files here are small (tens of lines), so the O(n·m)
114
+ * table is fine and we avoid pulling in a dep. */
115
+ function printUnifiedDiff(oldStr, newStr) {
116
+ const a = oldStr.split("\n");
117
+ const b = newStr.split("\n");
118
+ // LCS lengths table.
119
+ const lcs = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
120
+ for (let i = a.length - 1; i >= 0; i--) {
121
+ for (let j = b.length - 1; j >= 0; j--) {
122
+ lcs[i][j] = a[i] === b[j] ? lcs[i + 1][j + 1] + 1 : Math.max(lcs[i + 1][j], lcs[i][j + 1]);
123
+ }
124
+ }
125
+ // Walk the table emitting -/+/context lines.
126
+ let i = 0;
127
+ let j = 0;
128
+ while (i < a.length && j < b.length) {
129
+ if (a[i] === b[j]) {
130
+ i++;
131
+ j++;
132
+ }
133
+ else if (lcs[i + 1][j] >= lcs[i][j + 1]) {
134
+ console.log(chalk.red(` - ${a[i]}`));
135
+ i++;
136
+ }
137
+ else {
138
+ console.log(chalk.green(` + ${b[j]}`));
139
+ j++;
140
+ }
141
+ }
142
+ while (i < a.length)
143
+ console.log(chalk.red(` - ${a[i++]}`));
144
+ while (j < b.length)
145
+ console.log(chalk.green(` + ${b[j++]}`));
146
+ }
147
+ function configFromManifestAndTfvars(manifest, tfvarsPath) {
148
+ const tfvars = tfvarsPath && existsSync(tfvarsPath) ? readFileSync(tfvarsPath, "utf-8") : "";
149
+ const { baseDomain, subdomain } = parseDomain(manifest.domain);
150
+ return {
151
+ name: manifest.name,
152
+ domain: manifest.domain,
153
+ baseDomain,
154
+ subdomain,
155
+ surfaces: (manifest.surfaces ?? "both"),
156
+ deployTarget: manifest.deployTarget,
157
+ // Infra-only fields — preserved from the existing tfvars so we
158
+ // don't blow away discovered IPs / sizes.
159
+ serverIpv4: extractHcl(tfvars, "target_ipv4") || undefined,
160
+ serverIpv6: extractHcl(tfvars, "target_ipv6") || undefined,
161
+ serverSize: extractHcl(tfvars, "server_type") || undefined,
162
+ serverLocation: extractHcl(tfvars, "server_location") || undefined,
163
+ features: [...manifest.features],
164
+ s3Provider: manifest.s3Provider,
165
+ mlServices: [...manifest.mlServices],
166
+ forceRedeployMl: [],
167
+ gpuPlatforms: manifest.gpuPlatforms,
168
+ customHfModelId: manifest.customHfModelId,
169
+ customHfGpuType: manifest.customHfGpuType,
170
+ scaffoldRepo: false,
171
+ createGithubRepo: false,
172
+ installDeps: false,
173
+ runDeployment: false,
174
+ dryRun: false,
175
+ envValues: {},
176
+ };
177
+ }
178
+ /** Pull a top-level `key = "value"` line out of an HCL tfvars body.
179
+ * Tolerates leading whitespace; ignores values inside blocks. Returns
180
+ * the unquoted value, or "" when not found. */
181
+ function extractHcl(content, key) {
182
+ if (!content)
183
+ return "";
184
+ const m = content.match(new RegExp(`^\\s*${key}\\s*=\\s*"([^"]*)"`, "m"));
185
+ return m ? m[1] : "";
186
+ }
187
+ /** The DNS provider drives which dns-only stack dir we'd fall back to
188
+ * for a brand-new regen (when there's no existing tfvars to anchor
189
+ * on). Defaults to inwx, which matches `generateTfvars`'s own
190
+ * fallback. */
191
+ function inferDnsProviderFromConfig() {
192
+ return (getConfig().providers.dns?.provider ?? "inwx");
193
+ }
194
+ //# sourceMappingURL=regen-infra.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regen-infra.js","sourceRoot":"","sources":["../../src/deploy/regen-infra.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -152,6 +152,13 @@ async function main() {
152
152
  await runSyncCli(args.slice(1));
153
153
  break;
154
154
  }
155
+ case "regen-infra": {
156
+ if (args.includes("--help"))
157
+ return printHelp("regen-infra");
158
+ const { runRegenInfraCli } = await import("./deploy/regen-infra.js");
159
+ await runRegenInfraCli(args.slice(1), MONOREPO_ROOT);
160
+ break;
161
+ }
155
162
  case "doctor": {
156
163
  if (args.includes("--help"))
157
164
  return printHelp("doctor");
@@ -914,7 +921,11 @@ async function handleCreate() {
914
921
  // Auto-provision GlitchTip + write its DSN encrypted into
915
922
  // .env.production. The user picked the `analytics` feature; we
916
923
  // already verified GlitchTip is configured during pre-flight.
917
- if (config.features.includes("analytics")) {
924
+ // Skipped for client-only — the encrypt target lives in
925
+ // packages/server/, which doesn't exist post-prune. The client
926
+ // side of analytics (OpenPanel via NEXT_PUBLIC_*) still works
927
+ // without any provisioning.
928
+ if (config.features.includes("analytics") && config.surfaces !== "client-only") {
918
929
  try {
919
930
  const { provisionGlitchtipClient } = await import("./provision/glitchtip.js");
920
931
  const { set: dotenvxSet } = await import("@dotenvx/dotenvx");
@@ -937,8 +948,8 @@ async function handleCreate() {
937
948
  // · sandbox creds → .env.development (plaintext)
938
949
  // · live creds → .env.production (dotenvx-encrypted)
939
950
  // Webhook endpoint ids are tracked in keychain so destroy can
940
- // reach them later.
941
- if (config.features.includes("stripe")) {
951
+ // reach them later. Skipped for client-only (server-only feature).
952
+ if (config.features.includes("stripe") && config.surfaces !== "client-only") {
942
953
  try {
943
954
  const { provisionStripeProject, renderStripeEnv, renderStripeSkipComment } = await import("./provision/stripe.js");
944
955
  const { appendCommentBlock, parseEnvLines, writeDevEnv, writeProdEnv } = await import("./provision/write-env.js");
@@ -1203,7 +1214,12 @@ async function handleCreate() {
1203
1214
  // Final summary
1204
1215
  console.log(chalk.bold("\n ── Done! ─────────────────────────────────────────────────\n"));
1205
1216
  console.log(` App: ${chalk.cyan(`https://${config.domain}`)}`);
1206
- console.log(` API: ${chalk.cyan(`https://${config.domain}/api`)}`);
1217
+ // Skip the API line for client-only — there's no backend, so showing
1218
+ // a "/api" URL just confuses the user (and falsely implies a service
1219
+ // is listening at that path).
1220
+ if (config.surfaces !== "client-only") {
1221
+ console.log(` API: ${chalk.cyan(`https://${config.domain}/api`)}`);
1222
+ }
1207
1223
  console.log(` App dir: ${chalk.dim(appDir)}`);
1208
1224
  console.log(` Config: ${chalk.dim(getConfigPath())}`);
1209
1225
  if (config.scaffoldRepo) {
@@ -1800,6 +1816,40 @@ function printHelp(topic) {
1800
1816
  ${chalk.dim(" | jq 'with_entries(select(.key | startswith(\"traefik\")))'")}
1801
1817
  A correctly-synced container has 10+ traefik labels (HTTP router,
1802
1818
  HTTPS router with letsencrypt, gzip middleware, redirect-to-https).
1819
+ `);
1820
+ return;
1821
+ }
1822
+ if (topic === "regen-infra") {
1823
+ console.log(`
1824
+ ${chalk.bold("hatchkit regen-infra")} — rewrite tfvars + Coolify .env from the manifest
1825
+
1826
+ ${chalk.bold("Usage:")}
1827
+ cd <project-dir> && hatchkit regen-infra [--dry-run]
1828
+ hatchkit regen-infra --dir <project-dir> [--dry-run]
1829
+
1830
+ ${chalk.bold("What it does:")}
1831
+ Reads ${chalk.cyan(".hatchkit.json")}, re-runs the same generators ${chalk.cyan("hatchkit create")}
1832
+ uses (${chalk.dim("generateTfvars")} + ${chalk.dim("generateCoolifyEnv")}), and writes the result
1833
+ back to the existing tfvars + Coolify stack .env paths under
1834
+ ${chalk.dim("infra/")}. Infra-only fields the manifest doesn't carry (server IPs,
1835
+ Hetzner type/location) are preserved from the existing tfvars on
1836
+ disk, so a regen never silently blows away discovered values.
1837
+
1838
+ ${chalk.bold("When to use:")}
1839
+ · You upgraded the CLI and want existing projects to pick up the
1840
+ new tfvars logic (e.g. dropping the ${chalk.dim("api.<sub>")} subdomain for
1841
+ client-only surfaces).
1842
+ · You edited ${chalk.cyan(".hatchkit.json")} by hand (changed surfaces, added a
1843
+ feature) and want the infra files re-rendered to match.
1844
+
1845
+ ${chalk.bold("Out of scope:")}
1846
+ · Does NOT run terraform — review the diff, then
1847
+ ${chalk.dim("terraform -chdir=<stack> apply -var-file=<name>.tfvars")} yourself.
1848
+ · Does NOT touch Coolify live state — use ${chalk.cyan("hatchkit sync")} for that.
1849
+
1850
+ ${chalk.bold("Options:")}
1851
+ --dir <path> Project root (defaults to cwd).
1852
+ --dry-run Print the unified diff without writing.
1803
1853
  `);
1804
1854
  return;
1805
1855
  }