create-oke 0.10.3 → 0.11.0

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 (57) hide show
  1. package/README.md +2 -2
  2. package/package.json +2 -2
  3. package/src/ai-setup/apply.ts +113 -17
  4. package/src/ai-setup/catalog.ts +3 -3
  5. package/src/ai-setup/from-pref.ts +1 -1
  6. package/src/ai-setup/prompts.ts +1 -1
  7. package/src/cli.test.ts +183 -142
  8. package/src/cli.ts +190 -32
  9. package/src/create-defaults.test.ts +21 -15
  10. package/src/create-defaults.ts +33 -13
  11. package/src/customize-flow.test.ts +30 -35
  12. package/src/customize-flow.ts +68 -229
  13. package/src/drivers-catalog.ts +42 -48
  14. package/src/local-okengine.test.ts +50 -41
  15. package/src/local-okengine.ts +28 -14
  16. package/src/locales.test.ts +128 -0
  17. package/src/locales.ts +321 -0
  18. package/src/scaffold.ts +277 -33
  19. package/src/templates.ts +2 -8
  20. package/src/transform.test.ts +96 -36
  21. package/src/transform.ts +285 -110
  22. package/templates/advanced/.env.example +23 -3
  23. package/templates/advanced/README.md +1 -1
  24. package/templates/advanced/drizzle.config.ts +10 -13
  25. package/templates/advanced/oke.config.ts +12 -57
  26. package/templates/advanced/package.json +3 -1
  27. package/templates/advanced/src/app.ts +3 -10
  28. package/templates/advanced/src/core.ts +58 -0
  29. package/templates/advanced/src/db/schema.decl.ts +1 -1
  30. package/templates/advanced/src/db/seed/index.ts +2 -2
  31. package/templates/advanced/src/flows/notes/index.ts +1 -13
  32. package/templates/advanced/src/locales/index.ts +6 -0
  33. package/templates/advanced/tests/advanced.test.ts +1 -1
  34. package/templates/standard/.env.example +23 -3
  35. package/templates/standard/README.md +1 -1
  36. package/templates/standard/drizzle.config.ts +10 -13
  37. package/templates/standard/oke.config.ts +10 -56
  38. package/templates/standard/package.json +3 -1
  39. package/templates/standard/src/app.ts +3 -10
  40. package/templates/standard/src/core.ts +55 -0
  41. package/templates/standard/src/db/schema.decl.ts +1 -1
  42. package/templates/standard/src/db/seed/index.ts +2 -2
  43. package/templates/standard/src/flows/notes/index.ts +1 -10
  44. package/templates/standard/src/locales/index.ts +6 -0
  45. package/templates/standard/tests/standard.test.ts +1 -1
  46. package/templates/advanced/src/core/channels.ts +0 -13
  47. package/templates/advanced/src/core/gates.ts +0 -12
  48. package/templates/advanced/src/core/index.ts +0 -12
  49. package/templates/advanced/src/core/store.ts +0 -8
  50. package/templates/advanced/src/core/vault.ts +0 -7
  51. package/templates/advanced/src/locales/ar.ts +0 -18
  52. package/templates/standard/src/core/channels.ts +0 -13
  53. package/templates/standard/src/core/gates.ts +0 -12
  54. package/templates/standard/src/core/index.ts +0 -12
  55. package/templates/standard/src/core/store.ts +0 -5
  56. package/templates/standard/src/core/vault.ts +0 -7
  57. package/templates/standard/src/locales/ar.ts +0 -18
@@ -1,13 +1,12 @@
1
1
  /**
2
- * Unit tests for local|docker customize assembly (no Clack prompts).
2
+ * Unit tests for Docker-first customize assembly (no Clack prompts).
3
3
  */
4
4
 
5
5
  import { describe, expect, test } from "bun:test";
6
6
  import {
7
7
  EMAIL_CHOICES,
8
8
  INDEX_CHOICES,
9
- TEMPLATE_DOCKER_PROD,
10
- TEMPLATE_LOCAL,
9
+ TEMPLATE_DEV,
11
10
  customizeFacetsFor,
12
11
  } from "./drivers-catalog.ts";
13
12
  import { assembleDriverDefaults, pinsFromSides, recommendedAiApply } from "./customize-flow.ts";
@@ -37,7 +36,6 @@ describe("catalog labels", () => {
37
36
  "none",
38
37
  "memory",
39
38
  "pgvector",
40
- "libsql",
41
39
  "meilisearch",
42
40
  ]);
43
41
  });
@@ -52,7 +50,7 @@ describe("recommendedAiApply", () => {
52
50
  test("returns llama.cpp (openai-compatible) with curated ai/ model", () => {
53
51
  const apply = recommendedAiApply();
54
52
  expect(apply.driver).toBe("openai-compatible");
55
- expect(apply.chatModel).toBe("smollm2");
53
+ expect(apply.chatModel).toBe("granite3.3:2b");
56
54
  expect(apply.baseUrl).toContain("8080");
57
55
  expect(apply.image).toContain("llama.cpp");
58
56
  expect(apply.image).not.toContain("latest");
@@ -61,50 +59,47 @@ describe("recommendedAiApply", () => {
61
59
  });
62
60
 
63
61
  describe("pinsFromSides", () => {
64
- test("prod copies docker", () => {
65
- expect(pinsFromSides("sqlite", "postgres", "memory")).toEqual({
66
- local: "sqlite",
67
- docker: "postgres",
68
- test: "memory",
62
+ test("prod mirrors dev by default", () => {
63
+ expect(pinsFromSides("postgres", "pglite")).toEqual({
64
+ dev: "postgres",
65
+ test: "pglite",
69
66
  prod: "postgres",
70
67
  });
71
68
  });
72
69
  });
73
70
 
74
71
  describe("assembleDriverDefaults", () => {
75
- test("primary docker + skip other local pins === template defaults", () => {
76
- const drivers = assembleDriverDefaults(
77
- "docker",
78
- { sql: "libsql", kv: "redis", files: "s3", signal: "nats" },
79
- null,
80
- );
81
- expect(drivers.store.sql.docker).toBe("libsql");
82
- expect(drivers.store.sql.local).toBe(TEMPLATE_LOCAL.sql);
83
- expect(drivers.store.kv.local).toBe(TEMPLATE_LOCAL.kv);
84
- expect(drivers.signal.local).toBe(TEMPLATE_LOCAL.signal);
85
- expect(drivers.store.sql.prod).toBe("libsql");
72
+ test("picked sql + defaults for unpicked facets", () => {
73
+ const drivers = assembleDriverDefaults({
74
+ sql: "postgres",
75
+ kv: "redis",
76
+ files: "s3",
77
+ signal: "redis",
78
+ });
79
+ expect(drivers.store.sql.dev).toBe("postgres");
80
+ expect(drivers.store.sql.test).toBe("pglite");
81
+ expect(drivers.store.sql.prod).toBe("postgres");
82
+ expect(drivers.store.kv.dev).toBe("redis");
83
+ expect(drivers.signal.dev).toBe("redis");
84
+ expect(drivers.vault.dev).toBe(TEMPLATE_DEV.vault);
86
85
  });
87
86
 
88
- test("primary local + customize docker both sides set", () => {
89
- const drivers = assembleDriverDefaults("local", { sql: "pglite" }, { sql: "postgres" });
90
- expect(drivers.store.sql.local).toBe("pglite");
91
- expect(drivers.store.sql.docker).toBe("postgres");
92
- expect(drivers.store.sql.prod).toBe("postgres");
93
- // Unpicked facets fall back to catalog defaults.
94
- expect(drivers.store.kv.local).toBe(TEMPLATE_LOCAL.kv);
95
- expect(drivers.store.kv.docker).toBe(TEMPLATE_DOCKER_PROD.kv);
87
+ test("empty picktemplate Docker-first defaults", () => {
88
+ const drivers = assembleDriverDefaults({});
89
+ expect(drivers.store.sql.dev).toBe(TEMPLATE_DEV.sql);
90
+ expect(drivers.store.kv.dev).toBe(TEMPLATE_DEV.kv);
91
+ expect(drivers.store.sql.test).toBe("pglite");
96
92
  });
97
93
 
98
94
  test("index stays null for none / unset", () => {
99
- expect(assembleDriverDefaults("local", { sql: "sqlite" }, null).store.index).toBeNull();
100
- expect(assembleDriverDefaults("docker", { index: "none" }, null).store.index).toBeNull();
95
+ expect(assembleDriverDefaults({ sql: "postgres" }).store.index).toBeNull();
96
+ expect(assembleDriverDefaults({ index: "none" }).store.index).toBeNull();
101
97
  });
102
98
 
103
- test("index driver on primary fills both columns", () => {
104
- const drivers = assembleDriverDefaults("docker", { index: "meilisearch" }, null);
99
+ test("index driver fills both runtime columns", () => {
100
+ const drivers = assembleDriverDefaults({ index: "meilisearch" });
105
101
  expect(drivers.store.index).toEqual({
106
- local: "memory",
107
- docker: "meilisearch",
102
+ dev: "meilisearch",
108
103
  test: "memory",
109
104
  prod: "meilisearch",
110
105
  });
@@ -1,9 +1,7 @@
1
1
  /**
2
- * Customize wizard — pick local|docker first, walk facets for that side,
3
- * then ask whether to customize the other (defaults if no).
2
+ * Customize wizard — walk Docker-first facets once, assemble `{ dev, test, prod }`.
4
3
  */
5
4
 
6
- import { confirm, isCancel } from "@clack/prompts";
7
5
  import { toCreateDefaults, type CreateDefaults, type EnvDriverPins } from "./create-defaults.ts";
8
6
  import {
9
7
  CLOCK_CHOICES,
@@ -13,8 +11,7 @@ import {
13
11
  KV_CHOICES,
14
12
  SIGNAL_CHOICES,
15
13
  SQL_CHOICES,
16
- TEMPLATE_DOCKER_PROD,
17
- TEMPLATE_LOCAL,
14
+ TEMPLATE_DEV,
18
15
  TEMPLATE_TEST,
19
16
  VAULT_CHOICES,
20
17
  AI_PROVIDERS,
@@ -25,7 +22,7 @@ import {
25
22
  aiDriverForProvider,
26
23
  customizeFacetsFor,
27
24
  pinsDockerReady,
28
- pinsLocalOnly,
25
+ pinsEnv,
29
26
  type AiProviderId,
30
27
  type CustomizeFacetId,
31
28
  type DriverChoice,
@@ -39,10 +36,7 @@ import { WIZARD_BACK, selectWithBack, type WizardBack } from "./wizard-select.ts
39
36
  export type { WizardBack };
40
37
  export { WIZARD_BACK };
41
38
 
42
- /** Dev env column being customized. */
43
- export type CustomizeSide = "local" | "docker";
44
-
45
- /** Partial pins accumulated per side before merge. */
39
+ /** Partial pins accumulated before merge. */
46
40
  export type SidePins = {
47
41
  sql?: string;
48
42
  kv?: string;
@@ -56,14 +50,14 @@ export type SidePins = {
56
50
  };
57
51
 
58
52
  /**
59
- * Merge primary + other side into full {@link EnvDriverPins}.
53
+ * Assemble `{ dev, test, prod }` pins (prod mirrors dev).
60
54
  *
61
- * @param local - Local driver
62
- * @param docker - Docker driver (copied to prod)
55
+ * @param dev - Dev driver
63
56
  * @param test - Test pin
57
+ * @param prod - Prod pin (defaults to `dev`)
64
58
  */
65
- export function pinsFromSides(local: string, docker: string, test: string): EnvDriverPins {
66
- return { local, docker, test, prod: docker };
59
+ export function pinsFromSides(dev: string, test: string, prod: string = dev): EnvDriverPins {
60
+ return pinsEnv(dev, test, prod);
67
61
  }
68
62
 
69
63
  /**
@@ -76,69 +70,25 @@ function indexEnabled(value: string | null | undefined): value is string {
76
70
  }
77
71
 
78
72
  /**
79
- * Fill missing side from template defaults.
73
+ * Fill missing facets from template Docker-first defaults.
80
74
  *
81
- * @param side - Side that was customized
82
- * @param picked - Values chosen for that side
83
- * @param other - Optional values if the user also customized the other side
75
+ * @param picked - Values chosen during customize
84
76
  */
85
- export function assembleDriverDefaults(
86
- side: CustomizeSide,
87
- picked: SidePins,
88
- other: SidePins | null,
89
- ): CreateDefaults["drivers"] {
90
- const localSrc = side === "local" ? picked : (other ?? {});
91
- const dockerSrc = side === "docker" ? picked : (other ?? {});
92
-
93
- const sql = pinsFromSides(
94
- localSrc.sql ?? TEMPLATE_LOCAL.sql,
95
- dockerSrc.sql ?? TEMPLATE_DOCKER_PROD.sql,
96
- TEMPLATE_TEST.sql,
97
- );
98
- const kv = pinsFromSides(
99
- localSrc.kv ?? TEMPLATE_LOCAL.kv,
100
- dockerSrc.kv ?? TEMPLATE_DOCKER_PROD.kv,
101
- TEMPLATE_TEST.kv,
102
- );
103
- const files = pinsFromSides(
104
- localSrc.files ?? TEMPLATE_LOCAL.files,
105
- dockerSrc.files ?? TEMPLATE_DOCKER_PROD.files,
106
- TEMPLATE_TEST.files,
107
- );
108
- const indexLocal = localSrc.index;
109
- const indexDocker = dockerSrc.index;
110
- const index =
111
- indexEnabled(indexLocal) || indexEnabled(indexDocker)
112
- ? pinsFromSides(
113
- indexEnabled(indexLocal) ? indexLocal : "memory",
114
- indexEnabled(indexDocker) ? indexDocker : "meilisearch",
115
- "memory",
116
- )
117
- : null;
77
+ export function assembleDriverDefaults(picked: SidePins): CreateDefaults["drivers"] {
78
+ const sql = pinsFromSides(picked.sql ?? TEMPLATE_DEV.sql, TEMPLATE_TEST.sql);
79
+ const kv = pinsFromSides(picked.kv ?? TEMPLATE_DEV.kv, TEMPLATE_TEST.kv);
80
+ const files = pinsFromSides(picked.files ?? TEMPLATE_DEV.files, TEMPLATE_TEST.files);
81
+ const index = indexEnabled(picked.index)
82
+ ? pinsFromSides(picked.index, "memory", picked.index)
83
+ : null;
118
84
 
119
85
  return {
120
86
  store: { sql, kv, files, index },
121
- signal: pinsFromSides(
122
- localSrc.signal ?? TEMPLATE_LOCAL.signal,
123
- dockerSrc.signal ?? TEMPLATE_DOCKER_PROD.signal,
124
- TEMPLATE_TEST.signal,
125
- ),
126
- clock: pinsFromSides(
127
- localSrc.clock ?? TEMPLATE_LOCAL.clock,
128
- dockerSrc.clock ?? TEMPLATE_DOCKER_PROD.clock,
129
- TEMPLATE_TEST.clock,
130
- ),
131
- vault: pinsFromSides(
132
- localSrc.vault ?? TEMPLATE_LOCAL.vault,
133
- dockerSrc.vault ?? TEMPLATE_DOCKER_PROD.vault,
134
- TEMPLATE_TEST.vault,
135
- ),
87
+ signal: pinsFromSides(picked.signal ?? TEMPLATE_DEV.signal, TEMPLATE_TEST.signal),
88
+ clock: pinsFromSides(picked.clock ?? TEMPLATE_DEV.clock, TEMPLATE_TEST.clock),
89
+ vault: pinsFromSides(picked.vault ?? TEMPLATE_DEV.vault, TEMPLATE_TEST.vault),
136
90
  channel: {
137
- email: pinsFromSides(
138
- localSrc.email ?? TEMPLATE_LOCAL.email,
139
- dockerSrc.email ?? TEMPLATE_DOCKER_PROD.email,
140
- TEMPLATE_TEST.email,
141
- ),
91
+ email: pinsFromSides(picked.email ?? TEMPLATE_DEV.email, TEMPLATE_TEST.email),
142
92
  },
143
93
  ai: null,
144
94
  };
@@ -146,13 +96,13 @@ export function assembleDriverDefaults(
146
96
 
147
97
  /**
148
98
  * Balanced llama.cpp defaults for "AI setup → Recommended" (no quiz).
149
- * Lightest local footprint; curated Docker Hub `ai/` model via docker-repo.
99
+ * openai-compatible + curated Docker Hub `ai/` model (`granite3.3:2b`).
150
100
  */
151
101
  export function recommendedAiApply(): AiSetupApplyInput {
152
102
  return {
153
103
  driver: "openai-compatible",
154
104
  baseUrl: process.env.OKE_AI_URL ?? "http://127.0.0.1:8080/v1",
155
- chatModel: "smollm2",
105
+ chatModel: "granite3.3:2b",
156
106
  visionModel: null,
157
107
  embedModel: null,
158
108
  image: LLAMA_CPP_IMAGE,
@@ -201,56 +151,14 @@ export function withLocalAiImage(input: AiSetupApplyInput, provider: string): Ai
201
151
  export async function askCustomizeFlow(
202
152
  template: TemplateId,
203
153
  ): Promise<CreateDefaults | WizardBack | null> {
204
- const primaryValue = await selectWithBack(
205
- "Customize drivers for",
206
- [
207
- {
208
- value: "local",
209
- label: "Local",
210
- hint: "oke mode local — sqlite / memory / fs …",
211
- },
212
- {
213
- value: "docker",
214
- label: "Docker",
215
- hint: "oke mode docker — postgres / redis / s3 …",
216
- },
217
- ],
218
- template === "advanced" ? "docker" : "local",
219
- { allowBack: true },
220
- );
221
- if (primaryValue === null) return null;
222
- if (primaryValue === WIZARD_BACK) return WIZARD_BACK;
223
- const primary = primaryValue as CustomizeSide;
224
-
225
154
  const facets = customizeFacetsFor(template);
226
- const primaryPins = await walkFacetsForSide(facets, primary);
155
+ const primaryPins = await walkFacets(facets);
227
156
  if (primaryPins === null) return null;
228
157
  if (primaryPins === WIZARD_BACK) return WIZARD_BACK;
229
158
 
230
- const otherSide: CustomizeSide = primary === "local" ? "docker" : "local";
231
- const alsoOther = await confirm({
232
- message:
233
- otherSide === "local" ? "Also customize local drivers?" : "Also customize docker drivers?",
234
- initialValue: false,
235
- });
236
- if (isCancel(alsoOther)) return null;
237
-
238
- let otherPins: SidePins | null = null;
239
- if (alsoOther) {
240
- const walked = await walkFacetsForSide(facets, otherSide);
241
- if (walked === null) return null;
242
- if (walked === WIZARD_BACK) {
243
- // Back from other side → treat as "no, use defaults"
244
- otherPins = null;
245
- } else {
246
- otherPins = walked;
247
- }
248
- }
249
-
250
- const drivers = assembleDriverDefaults(primary, primaryPins, otherPins);
251
- const profile = primary === "docker" ? "docker-ready" : "local-only";
159
+ const drivers = assembleDriverDefaults(primaryPins);
252
160
 
253
- // AI — after env passes
161
+ // AI — after env pass
254
162
  let aiPins: EnvDriverPins | null = null;
255
163
  let aiPref: CreateDefaults["ai"] = { enabled: false, provider: null, driver: null };
256
164
  let aiApply: AiSetupApplyInput | null = null;
@@ -262,7 +170,7 @@ export async function askCustomizeFlow(
262
170
  {
263
171
  value: "recommended",
264
172
  label: "Recommended",
265
- hint: "llama.cpp · lightest local footprint",
173
+ hint: "llama.cpp · openai-compatible · granite3.3:2b",
266
174
  },
267
175
  {
268
176
  value: "customize",
@@ -280,15 +188,11 @@ export async function askCustomizeFlow(
280
188
  );
281
189
  if (aiSetup === null) return null;
282
190
  if (aiSetup === WIZARD_BACK) {
283
- // Back from AI → leave AI off (same as Off) and finish customize.
284
191
  break;
285
192
  }
286
193
  if (aiSetup === "off") break;
287
194
  if (aiSetup === "recommended") {
288
- aiPins =
289
- primary === "local" && !alsoOther
290
- ? pinsLocalOnly("openai-compatible", "openai-compatible", "mock")
291
- : pinsDockerReady("openai-compatible", "openai-compatible", "mock");
195
+ aiPins = pinsDockerReady("openai-compatible", "mock");
292
196
  aiApply = recommendedAiApply();
293
197
  aiPref = aiPrefWithModels(
294
198
  {
@@ -301,91 +205,60 @@ export async function askCustomizeFlow(
301
205
  break;
302
206
  }
303
207
 
304
- // customize — local provider, optional docker provider, then model wizard
305
208
  const options = AI_PROVIDERS.map((p) => ({ value: p.value, label: p.label }));
306
- providers: for (;;) {
307
- const askDockerAi = primary === "docker" || alsoOther;
308
- const localProviderValue = await selectWithBack(
309
- askDockerAi || primary === "local" ? "AI Provider — local" : "AI Provider",
310
- options,
311
- "llama-cpp",
312
- { allowBack: true },
313
- );
314
- if (localProviderValue === null) return null;
315
- if (localProviderValue === WIZARD_BACK) continue aiSetup;
316
-
317
- const localProvider = localProviderValue as AiProviderId;
318
- const localDriver = aiDriverForProvider(localProvider);
319
- let dockerDriver = localDriver === "mock" ? "mock" : localDriver;
320
- let dockerProvider: AiProviderId = localProvider;
321
-
322
- if (askDockerAi) {
323
- const dockerProviderValue = await selectWithBack(
324
- "AI Provider — docker",
325
- options,
326
- "llama-cpp",
327
- { allowBack: true },
328
- );
329
- if (dockerProviderValue === null) return null;
330
- if (dockerProviderValue === WIZARD_BACK) continue providers;
331
- dockerProvider = dockerProviderValue as AiProviderId;
332
- dockerDriver = aiDriverForProvider(dockerProvider);
333
- if (dockerDriver === "mock") dockerDriver = "mock";
334
- }
209
+ const providerValue = await selectWithBack("AI Provider", options, "llama-cpp", {
210
+ allowBack: true,
211
+ });
212
+ if (providerValue === null) return null;
213
+ if (providerValue === WIZARD_BACK) continue;
335
214
 
336
- aiPins =
337
- primary === "local" && !alsoOther
338
- ? pinsLocalOnly(localDriver, dockerDriver, "mock")
339
- : pinsDockerReady(localDriver, dockerDriver, "mock");
215
+ const provider = providerValue as AiProviderId;
216
+ const driver = aiDriverForProvider(provider);
217
+ aiPins = pinsDockerReady(driver, "mock");
340
218
 
341
- const setupProvider =
342
- localProvider === "ollama" || aiPins.local === "ollama" || aiPins.docker === "ollama"
343
- ? "ollama"
344
- : localProvider;
345
-
346
- if (setupProvider !== "mock") {
347
- const picked = await askAiSetup({ provider: setupProvider });
348
- if (picked === null) return null;
349
- aiApply = withLocalAiImage(picked, askDockerAi ? dockerProvider : localProvider);
350
- } else {
351
- aiApply = { driver: "mock" };
352
- }
353
-
354
- aiPref = aiPrefWithModels(
355
- {
356
- enabled: true,
357
- provider: setupProvider,
358
- driver: aiPins.local,
359
- },
360
- aiApply,
361
- );
362
- break aiSetup;
219
+ if (provider !== "mock") {
220
+ const picked = await askAiSetup({ provider });
221
+ if (picked === null) return null;
222
+ aiApply = withLocalAiImage(picked, provider);
223
+ } else {
224
+ aiApply = { driver: "mock" };
363
225
  }
226
+
227
+ aiPref = aiPrefWithModels(
228
+ {
229
+ enabled: true,
230
+ provider,
231
+ driver: aiPins.dev,
232
+ },
233
+ aiApply,
234
+ );
235
+ break;
364
236
  }
365
237
 
366
238
  return toCreateDefaults({
367
239
  template,
368
- profile,
240
+ profile: "docker-ready",
369
241
  drivers: { ...drivers, ai: aiPins },
370
242
  ai: aiPref,
243
+ // Locales / PgDog are asked once in the main wizard (not per customize pass).
244
+ locales: [],
245
+ pgdog: false,
371
246
  });
372
247
  }
373
248
 
374
249
  /**
375
- * Walk facet prompts for one env side.
250
+ * Walk facet prompts for the Docker-first runtime.
376
251
  *
377
252
  * @param facets - Facet ids for the template
378
- * @param side - local or docker
379
253
  */
380
- async function walkFacetsForSide(
254
+ async function walkFacets(
381
255
  facets: readonly CustomizeFacetId[],
382
- side: CustomizeSide,
383
256
  ): Promise<SidePins | WizardBack | null> {
384
257
  const out: SidePins = {};
385
258
  let i = 0;
386
259
  while (i < facets.length) {
387
260
  const facet = facets[i]!;
388
- const result = await askOneFacet(facet, side, out);
261
+ const result = await askOneFacet(facet, out);
389
262
  if (result === null) return null;
390
263
  if (result === WIZARD_BACK) {
391
264
  if (i === 0) return WIZARD_BACK;
@@ -399,87 +272,53 @@ async function walkFacetsForSide(
399
272
 
400
273
  async function askOneFacet(
401
274
  facet: CustomizeFacetId,
402
- side: CustomizeSide,
403
275
  state: SidePins,
404
276
  ): Promise<true | WizardBack | null> {
405
- const suffix = side === "local" ? "local" : "docker";
406
277
  switch (facet) {
407
278
  case "sql": {
408
- const v = await askSideChoice(
409
- `store.sql — ${suffix}`,
410
- SQL_CHOICES,
411
- side === "local" ? TEMPLATE_LOCAL.sql : TEMPLATE_DOCKER_PROD.sql,
412
- );
279
+ const v = await askSideChoice("store.sql — dev/prod", SQL_CHOICES, TEMPLATE_DEV.sql);
413
280
  if (v === null || v === WIZARD_BACK) return v;
414
281
  state.sql = v;
415
282
  return true;
416
283
  }
417
284
  case "kv": {
418
- const v = await askSideChoice(
419
- `store.kv — ${suffix}`,
420
- KV_CHOICES,
421
- side === "local" ? TEMPLATE_LOCAL.kv : TEMPLATE_DOCKER_PROD.kv,
422
- );
285
+ const v = await askSideChoice("store.kv — dev/prod", KV_CHOICES, TEMPLATE_DEV.kv);
423
286
  if (v === null || v === WIZARD_BACK) return v;
424
287
  state.kv = v;
425
288
  return true;
426
289
  }
427
290
  case "files": {
428
- const v = await askSideChoice(
429
- `store.files — ${suffix}`,
430
- FILES_CHOICES,
431
- side === "local" ? TEMPLATE_LOCAL.files : TEMPLATE_DOCKER_PROD.files,
432
- );
291
+ const v = await askSideChoice("store.files — dev/prod", FILES_CHOICES, TEMPLATE_DEV.files);
433
292
  if (v === null || v === WIZARD_BACK) return v;
434
293
  state.files = v;
435
294
  return true;
436
295
  }
437
296
  case "index": {
438
- const v = await askSideChoice(
439
- `store.index — ${suffix}`,
440
- INDEX_CHOICES,
441
- side === "local" ? "none" : "meilisearch",
442
- );
297
+ const v = await askSideChoice("store.index — dev/prod", INDEX_CHOICES, "meilisearch");
443
298
  if (v === null || v === WIZARD_BACK) return v;
444
299
  state.index = v;
445
300
  return true;
446
301
  }
447
302
  case "signal": {
448
- const v = await askSideChoice(
449
- `signal — ${suffix}`,
450
- SIGNAL_CHOICES,
451
- side === "local" ? TEMPLATE_LOCAL.signal : TEMPLATE_DOCKER_PROD.signal,
452
- );
303
+ const v = await askSideChoice("signal — dev/prod", SIGNAL_CHOICES, TEMPLATE_DEV.signal);
453
304
  if (v === null || v === WIZARD_BACK) return v;
454
305
  state.signal = v;
455
306
  return true;
456
307
  }
457
308
  case "clock": {
458
- const v = await askSideChoice(
459
- `clock — ${suffix}`,
460
- CLOCK_CHOICES,
461
- side === "local" ? TEMPLATE_LOCAL.clock : TEMPLATE_DOCKER_PROD.clock,
462
- );
309
+ const v = await askSideChoice("clock — dev/prod", CLOCK_CHOICES, TEMPLATE_DEV.clock);
463
310
  if (v === null || v === WIZARD_BACK) return v;
464
311
  state.clock = v;
465
312
  return true;
466
313
  }
467
314
  case "vault": {
468
- const v = await askSideChoice(
469
- `vault — ${suffix}`,
470
- VAULT_CHOICES,
471
- side === "local" ? TEMPLATE_LOCAL.vault : TEMPLATE_DOCKER_PROD.vault,
472
- );
315
+ const v = await askSideChoice("vault — dev/prod", VAULT_CHOICES, TEMPLATE_DEV.vault);
473
316
  if (v === null || v === WIZARD_BACK) return v;
474
317
  state.vault = v;
475
318
  return true;
476
319
  }
477
320
  case "email": {
478
- const v = await askSideChoice(
479
- `channel.email — ${suffix}`,
480
- EMAIL_CHOICES,
481
- side === "local" ? TEMPLATE_LOCAL.email : TEMPLATE_DOCKER_PROD.email,
482
- );
321
+ const v = await askSideChoice("channel.email — dev/prod", EMAIL_CHOICES, TEMPLATE_DEV.email);
483
322
  if (v === null || v === WIZARD_BACK) return v;
484
323
  state.email = v;
485
324
  return true;