@korajs/cli 0.3.2 → 0.3.4

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 (48) hide show
  1. package/dist/bin.cjs +120 -67
  2. package/dist/bin.cjs.map +1 -1
  3. package/dist/bin.js +3 -3
  4. package/dist/{chunk-KTSRAPSE.js → chunk-HNVCNPER.js} +105 -65
  5. package/dist/chunk-HNVCNPER.js.map +1 -0
  6. package/dist/{chunk-E7OCVRYL.js → chunk-MIMLCXSX.js} +2 -2
  7. package/dist/{chunk-ZGYRDYXS.js → chunk-ULTO5NFA.js} +22 -4
  8. package/dist/chunk-ULTO5NFA.js.map +1 -0
  9. package/dist/create.cjs +119 -66
  10. package/dist/create.cjs.map +1 -1
  11. package/dist/create.js +2 -2
  12. package/dist/index.cjs +105 -65
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.cts +6 -1
  15. package/dist/index.d.ts +6 -1
  16. package/dist/index.js +2 -2
  17. package/package.json +1 -1
  18. package/templates/tauri-react/.env.example +7 -0
  19. package/templates/tauri-react/.github/workflows/release-desktop.yml +107 -0
  20. package/templates/tauri-react/README.md.hbs +148 -0
  21. package/templates/tauri-react/dev.ts +37 -0
  22. package/templates/tauri-react/index.html.hbs +16 -0
  23. package/templates/tauri-react/kora.config.ts +17 -0
  24. package/templates/tauri-react/package.json.hbs +44 -0
  25. package/templates/tauri-react/server.ts +23 -0
  26. package/templates/tauri-react/src/App.tsx +578 -0
  27. package/templates/tauri-react/src/AppShell.tsx +116 -0
  28. package/templates/tauri-react/src/SetupScreen.tsx +239 -0
  29. package/templates/tauri-react/src/main.tsx +9 -0
  30. package/templates/tauri-react/src/schema.ts +15 -0
  31. package/templates/tauri-react/src/sync-config.ts +103 -0
  32. package/templates/tauri-react/src/updater.ts +38 -0
  33. package/templates/tauri-react/src-tauri/Cargo.toml +19 -0
  34. package/templates/tauri-react/src-tauri/build.rs +3 -0
  35. package/templates/tauri-react/src-tauri/capabilities/default.json +12 -0
  36. package/templates/tauri-react/src-tauri/icons/128x128.png +0 -0
  37. package/templates/tauri-react/src-tauri/icons/128x128@2x.png +0 -0
  38. package/templates/tauri-react/src-tauri/icons/32x32.png +0 -0
  39. package/templates/tauri-react/src-tauri/icons/icon.icns +0 -0
  40. package/templates/tauri-react/src-tauri/icons/icon.ico +0 -0
  41. package/templates/tauri-react/src-tauri/src/lib.rs +8 -0
  42. package/templates/tauri-react/src-tauri/src/main.rs +6 -0
  43. package/templates/tauri-react/src-tauri/tauri.conf.json +44 -0
  44. package/templates/tauri-react/tsconfig.json +15 -0
  45. package/templates/tauri-react/vite.config.ts +15 -0
  46. package/dist/chunk-KTSRAPSE.js.map +0 -1
  47. package/dist/chunk-ZGYRDYXS.js.map +0 -1
  48. /package/dist/{chunk-E7OCVRYL.js.map → chunk-MIMLCXSX.js.map} +0 -0
package/dist/bin.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createCommand
4
- } from "./chunk-ZGYRDYXS.js";
4
+ } from "./chunk-ULTO5NFA.js";
5
5
  import {
6
6
  deployCommand,
7
7
  generateTypes
8
- } from "./chunk-E7OCVRYL.js";
8
+ } from "./chunk-MIMLCXSX.js";
9
9
  import {
10
10
  DevServerError,
11
11
  InvalidProjectError,
@@ -16,7 +16,7 @@ import {
16
16
  hasTsxInstalled,
17
17
  promptConfirm,
18
18
  resolveProjectBinaryEntryPoint
19
- } from "./chunk-KTSRAPSE.js";
19
+ } from "./chunk-HNVCNPER.js";
20
20
 
21
21
  // src/bin.ts
22
22
  import { defineCommand as defineCommand4, runMain } from "citty";
@@ -62,6 +62,7 @@ var DevServerError = class extends KoraError {
62
62
  // src/prompts/preferences.ts
63
63
  import Conf from "conf";
64
64
  var DEFAULT_PREFERENCES = {
65
+ platform: "web",
65
66
  framework: "react",
66
67
  tailwind: true,
67
68
  sync: true,
@@ -276,7 +277,8 @@ var TEMPLATES = [
276
277
  "react-tailwind-sync",
277
278
  "react-tailwind",
278
279
  "react-sync",
279
- "react-basic"
280
+ "react-basic",
281
+ "tauri-react"
280
282
  ];
281
283
  var TEMPLATE_INFO = [
282
284
  {
@@ -298,17 +300,26 @@ var TEMPLATE_INFO = [
298
300
  name: "react-basic",
299
301
  label: "React + CSS (local-only)",
300
302
  description: "Clean CSS app \u2014 no sync server"
303
+ },
304
+ {
305
+ name: "tauri-react",
306
+ label: "Tauri Desktop (native SQLite)",
307
+ description: "Desktop app with native SQLite \u2014 no WASM, includes sync server"
301
308
  }
302
309
  ];
303
310
 
304
311
  // src/commands/create/options.ts
305
312
  function determineTemplateFromSelections(input) {
313
+ if (input.platform === "desktop-tauri") return "tauri-react";
306
314
  const shouldSync = input.sync && input.db !== "none";
307
315
  if (input.tailwind && shouldSync) return "react-tailwind-sync";
308
316
  if (input.tailwind && !shouldSync) return "react-tailwind";
309
317
  if (!input.tailwind && shouldSync) return "react-sync";
310
318
  return "react-basic";
311
319
  }
320
+ function isPlatformValue(value) {
321
+ return value === "web" || value === "desktop-tauri";
322
+ }
312
323
  function isFrameworkValue(value) {
313
324
  return value === "react" || value === "vue" || value === "svelte" || value === "solid";
314
325
  }
@@ -343,83 +354,108 @@ async function resolveCreatePreferencesFlow(params) {
343
354
  usedStoredPreferences = true;
344
355
  }
345
356
  }
346
- if (flags.framework !== void 0) {
347
- if (!isFrameworkValue(flags.framework)) {
357
+ if (flags.platform !== void 0) {
358
+ if (!isPlatformValue(flags.platform)) {
348
359
  throw new Error(
349
- `Invalid --framework value "${flags.framework}". Expected one of: react, vue, svelte, solid.`
360
+ `Invalid --platform value "${flags.platform}". Expected one of: web, desktop-tauri.`
350
361
  );
351
362
  }
352
- effective.framework = flags.framework;
363
+ effective.platform = flags.platform;
353
364
  } else if (!flags.useDefaults && !usedStoredPreferences) {
354
- effective.framework = await prompts.select("UI framework:", [
355
- { label: "React", value: "react" },
356
- { label: "Vue (coming soon)", value: "vue", disabled: true },
357
- { label: "Svelte (coming soon)", value: "svelte", disabled: true },
358
- { label: "Solid (coming soon)", value: "solid", disabled: true }
365
+ effective.platform = await prompts.select("Platform:", [
366
+ { label: "Web (browser)", value: "web" },
367
+ { label: "Desktop (Tauri \u2014 native SQLite)", value: "desktop-tauri" }
359
368
  ]);
360
369
  }
361
- if (flags.auth !== void 0) {
362
- if (!isAuthValue(flags.auth)) {
363
- throw new Error(
364
- `Invalid --auth value "${flags.auth}". Expected one of: none, email-password, oauth.`
365
- );
370
+ const isTauri = effective.platform === "desktop-tauri";
371
+ if (isTauri) {
372
+ effective.framework = "react";
373
+ effective.tailwind = false;
374
+ effective.sync = true;
375
+ effective.db = "sqlite";
376
+ effective.dbProvider = "none";
377
+ effective.auth = "none";
378
+ } else {
379
+ if (flags.framework !== void 0) {
380
+ if (!isFrameworkValue(flags.framework)) {
381
+ throw new Error(
382
+ `Invalid --framework value "${flags.framework}". Expected one of: react, vue, svelte, solid.`
383
+ );
384
+ }
385
+ effective.framework = flags.framework;
386
+ } else if (!flags.useDefaults && !usedStoredPreferences) {
387
+ effective.framework = await prompts.select("UI framework:", [
388
+ { label: "React", value: "react" },
389
+ { label: "Vue (coming soon)", value: "vue", disabled: true },
390
+ { label: "Svelte (coming soon)", value: "svelte", disabled: true },
391
+ { label: "Solid (coming soon)", value: "solid", disabled: true }
392
+ ]);
366
393
  }
367
- effective.auth = flags.auth;
368
- } else if (!flags.useDefaults && !usedStoredPreferences) {
369
- effective.auth = await prompts.select("Authentication:", [
370
- { label: "None", value: "none" },
371
- { label: "Email + Password (coming soon)", value: "email-password", disabled: true },
372
- { label: "OAuth (coming soon)", value: "oauth", disabled: true }
373
- ]);
374
- }
375
- if (flags.tailwind !== void 0) {
376
- effective.tailwind = flags.tailwind;
377
- } else if (!flags.useDefaults && !usedStoredPreferences) {
378
- effective.tailwind = await prompts.confirm("Use Tailwind CSS?", true);
379
- }
380
- if (flags.sync !== void 0) {
381
- effective.sync = flags.sync;
382
- } else if (!flags.useDefaults && !usedStoredPreferences) {
383
- effective.sync = await prompts.confirm("Enable multi-device sync?", true);
384
- }
385
- if (flags.db !== void 0) {
386
- if (!isDatabaseValue(flags.db)) {
387
- throw new Error(`Invalid --db value "${flags.db}". Expected one of: none, sqlite, postgres.`);
394
+ if (flags.auth !== void 0) {
395
+ if (!isAuthValue(flags.auth)) {
396
+ throw new Error(
397
+ `Invalid --auth value "${flags.auth}". Expected one of: none, email-password, oauth.`
398
+ );
399
+ }
400
+ effective.auth = flags.auth;
401
+ } else if (!flags.useDefaults && !usedStoredPreferences) {
402
+ effective.auth = await prompts.select("Authentication:", [
403
+ { label: "None", value: "none" },
404
+ { label: "Email + Password (coming soon)", value: "email-password", disabled: true },
405
+ { label: "OAuth (coming soon)", value: "oauth", disabled: true }
406
+ ]);
388
407
  }
389
- effective.db = flags.db;
390
- } else if (!effective.sync) {
391
- effective.db = "none";
392
- } else if (!flags.useDefaults && !usedStoredPreferences) {
393
- effective.db = await prompts.select("Server-side database:", [
394
- { label: "SQLite (zero-config)", value: "sqlite" },
395
- { label: "PostgreSQL (production-scale)", value: "postgres" }
396
- ]);
397
- }
398
- if (effective.db !== "postgres") {
399
- effective.dbProvider = "none";
400
- } else if (flags.dbProvider !== void 0) {
401
- if (!isDatabaseProviderValue(flags.dbProvider)) {
402
- throw new Error(
403
- `Invalid --db-provider value "${flags.dbProvider}". Expected one of: none, local, supabase, neon, railway, vercel-postgres, custom.`
404
- );
408
+ if (flags.tailwind !== void 0) {
409
+ effective.tailwind = flags.tailwind;
410
+ } else if (!flags.useDefaults && !usedStoredPreferences) {
411
+ effective.tailwind = await prompts.confirm("Use Tailwind CSS?", true);
412
+ }
413
+ if (flags.sync !== void 0) {
414
+ effective.sync = flags.sync;
415
+ } else if (!flags.useDefaults && !usedStoredPreferences) {
416
+ effective.sync = await prompts.confirm("Enable multi-device sync?", true);
417
+ }
418
+ if (flags.db !== void 0) {
419
+ if (!isDatabaseValue(flags.db)) {
420
+ throw new Error(`Invalid --db value "${flags.db}". Expected one of: none, sqlite, postgres.`);
421
+ }
422
+ effective.db = flags.db;
423
+ } else if (!effective.sync) {
424
+ effective.db = "none";
425
+ } else if (!flags.useDefaults && !usedStoredPreferences) {
426
+ effective.db = await prompts.select("Server-side database:", [
427
+ { label: "SQLite (zero-config)", value: "sqlite" },
428
+ { label: "PostgreSQL (production-scale)", value: "postgres" }
429
+ ]);
430
+ }
431
+ if (effective.db !== "postgres") {
432
+ effective.dbProvider = "none";
433
+ } else if (flags.dbProvider !== void 0) {
434
+ if (!isDatabaseProviderValue(flags.dbProvider)) {
435
+ throw new Error(
436
+ `Invalid --db-provider value "${flags.dbProvider}". Expected one of: none, local, supabase, neon, railway, vercel-postgres, custom.`
437
+ );
438
+ }
439
+ effective.dbProvider = flags.dbProvider;
440
+ } else if (!flags.useDefaults && !usedStoredPreferences) {
441
+ effective.dbProvider = await prompts.select("Database provider:", [
442
+ { label: "Local Postgres", value: "local" },
443
+ { label: "Supabase", value: "supabase" },
444
+ { label: "Neon", value: "neon" },
445
+ { label: "Railway", value: "railway" },
446
+ { label: "Vercel Postgres", value: "vercel-postgres" },
447
+ { label: "Custom connection string", value: "custom" }
448
+ ]);
405
449
  }
406
- effective.dbProvider = flags.dbProvider;
407
- } else if (!flags.useDefaults && !usedStoredPreferences) {
408
- effective.dbProvider = await prompts.select("Database provider:", [
409
- { label: "Local Postgres", value: "local" },
410
- { label: "Supabase", value: "supabase" },
411
- { label: "Neon", value: "neon" },
412
- { label: "Railway", value: "railway" },
413
- { label: "Vercel Postgres", value: "vercel-postgres" },
414
- { label: "Custom connection string", value: "custom" }
415
- ]);
416
450
  }
417
451
  const template = determineTemplateFromSelections({
452
+ platform: effective.platform,
418
453
  tailwind: effective.tailwind,
419
454
  sync: effective.sync,
420
455
  db: effective.db
421
456
  });
422
457
  return {
458
+ platform: effective.platform,
423
459
  framework: effective.framework,
424
460
  auth: effective.auth,
425
461
  db: effective.db,
@@ -435,6 +471,7 @@ function shouldSavePreferences(flags) {
435
471
  }
436
472
  function saveResolvedPreferences(store, resolution) {
437
473
  store.saveCreatePreferences({
474
+ platform: resolution.platform,
438
475
  framework: resolution.framework,
439
476
  tailwind: resolution.tailwind,
440
477
  sync: resolution.sync,
@@ -445,12 +482,15 @@ function saveResolvedPreferences(store, resolution) {
445
482
  });
446
483
  }
447
484
  function hasExplicitPreferenceFlags(flags) {
448
- return flags.framework !== void 0 || flags.auth !== void 0 || flags.db !== void 0 || flags.dbProvider !== void 0 || flags.tailwind !== void 0 || flags.sync !== void 0;
485
+ return flags.platform !== void 0 || flags.framework !== void 0 || flags.auth !== void 0 || flags.db !== void 0 || flags.dbProvider !== void 0 || flags.tailwind !== void 0 || flags.sync !== void 0;
449
486
  }
450
487
  function promptSupportsRichOptions() {
451
488
  return typeof process !== "undefined" && process.stdin.isTTY && process.stdout.isTTY;
452
489
  }
453
490
  function formatStoredPreferenceLabel(preferences) {
491
+ if (preferences.platform === "desktop-tauri") {
492
+ return `Use previous settings (tauri-desktop + ${preferences.packageManager})`;
493
+ }
454
494
  const syncLabel = preferences.sync ? `sync/${preferences.db}` : "local-only";
455
495
  const styleLabel = preferences.tailwind ? "tailwind" : "css";
456
496
  return `Use previous settings (${preferences.framework} + ${styleLabel} + ${syncLabel} + ${preferences.packageManager})`;
@@ -552,7 +592,7 @@ async function applySyncProviderPreset(options) {
552
592
  await writeFile(readmePath, readmeTemplate, "utf-8");
553
593
  }
554
594
  function isSyncTemplate(template) {
555
- return template === "react-sync" || template === "react-tailwind-sync";
595
+ return template === "react-sync" || template === "react-tailwind-sync" || template === "tauri-react";
556
596
  }
557
597
  function getProviderDisplayName(provider) {
558
598
  switch (provider) {
@@ -749,4 +789,4 @@ export {
749
789
  validateProjectName,
750
790
  applySyncProviderPreset
751
791
  };
752
- //# sourceMappingURL=chunk-KTSRAPSE.js.map
792
+ //# sourceMappingURL=chunk-HNVCNPER.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/prompts/preferences.ts","../src/prompts/prompt-client.ts","../src/utils/prompt.ts","../src/types.ts","../src/commands/create/options.ts","../src/commands/create/preferences-flow.ts","../src/commands/create/project-name.ts","../src/commands/create/sync-provider-preset.ts","../src/utils/fs-helpers.ts","../src/utils/logger.ts"],"sourcesContent":["import { KoraError } from '@korajs/core'\n\n/**\n * Base error class for all CLI errors.\n */\nexport class CliError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'CLI_ERROR', context)\n\t\tthis.name = 'CliError'\n\t}\n}\n\n/**\n * Thrown when the target project directory already exists.\n */\nexport class ProjectExistsError extends KoraError {\n\tconstructor(public readonly directory: string) {\n\t\tsuper(\n\t\t\t`Directory \"${directory}\" already exists. Choose a different name or remove the existing directory.`,\n\t\t\t'PROJECT_EXISTS',\n\t\t\t{ directory },\n\t\t)\n\t\tthis.name = 'ProjectExistsError'\n\t}\n}\n\n/**\n * Thrown when a schema file cannot be found in the project.\n */\nexport class SchemaNotFoundError extends KoraError {\n\tconstructor(public readonly searchedPaths: string[]) {\n\t\tsuper(\n\t\t\t`Could not find a schema file. Searched: ${searchedPaths.join(', ')}. Create a schema file using defineSchema() from @korajs/core.`,\n\t\t\t'SCHEMA_NOT_FOUND',\n\t\t\t{ searchedPaths },\n\t\t)\n\t\tthis.name = 'SchemaNotFoundError'\n\t}\n}\n\n/**\n * Thrown when a command is run outside a valid Kora project.\n */\nexport class InvalidProjectError extends KoraError {\n\tconstructor(public readonly directory: string) {\n\t\tsuper(\n\t\t\t`\"${directory}\" is not a valid Kora project. No package.json with a kora dependency found. Run this command from inside a Kora project.`,\n\t\t\t'INVALID_PROJECT',\n\t\t\t{ directory },\n\t\t)\n\t\tthis.name = 'InvalidProjectError'\n\t}\n}\n\n/**\n * Thrown when a required local dev server binary cannot be found.\n */\nexport class DevServerError extends KoraError {\n\tconstructor(\n\t\tpublic readonly binary: string,\n\t\tpublic readonly searchPath: string,\n\t) {\n\t\tsuper(\n\t\t\t`Could not find required binary \"${binary}\" at ${searchPath}. Install project dependencies and try again.`,\n\t\t\t'DEV_SERVER_ERROR',\n\t\t\t{ binary, searchPath },\n\t\t)\n\t\tthis.name = 'DevServerError'\n\t}\n}\n","import Conf from 'conf'\nimport type { AuthOption, DatabaseOption, DatabaseProviderOption, FrameworkOption, PlatformOption } from '../commands/create/options'\nimport type { PackageManager } from '../types'\n\nexport interface CreatePreferences {\n\tplatform: PlatformOption\n\tframework: FrameworkOption\n\ttailwind: boolean\n\tsync: boolean\n\tdb: DatabaseOption\n\tdbProvider: DatabaseProviderOption\n\tauth: AuthOption\n\tpackageManager: PackageManager\n}\n\nconst DEFAULT_PREFERENCES: CreatePreferences = {\n\tplatform: 'web',\n\tframework: 'react',\n\ttailwind: true,\n\tsync: true,\n\tdb: 'sqlite',\n\tdbProvider: 'none',\n\tauth: 'none',\n\tpackageManager: 'pnpm',\n}\n\nconst PREFERENCES_KEY = 'create.defaults'\n\n/**\n * Preference store for scaffold-time defaults in `create-kora-app`.\n */\nexport class PreferenceStore {\n\tprivate readonly store: Conf<{ [PREFERENCES_KEY]?: CreatePreferences }>\n\n\tpublic constructor() {\n\t\tthis.store = new Conf<{ [PREFERENCES_KEY]?: CreatePreferences }>({\n\t\t\tprojectName: 'korajs-cli',\n\t\t})\n\t}\n\n\tpublic getCreatePreferences(): CreatePreferences | null {\n\t\treturn this.store.get(PREFERENCES_KEY) ?? null\n\t}\n\n\tpublic saveCreatePreferences(preferences: CreatePreferences): void {\n\t\tthis.store.set(PREFERENCES_KEY, preferences)\n\t}\n\n\tpublic clearCreatePreferences(): void {\n\t\tthis.store.delete(PREFERENCES_KEY)\n\t}\n}\n\n/**\n * Gets preferences from storage or returns defaults when not available.\n */\nexport function getCreatePreferencesOrDefault(store: PreferenceStore): CreatePreferences {\n\treturn store.getCreatePreferences() ?? DEFAULT_PREFERENCES\n}\n\nexport function getDefaultCreatePreferences(): CreatePreferences {\n\treturn { ...DEFAULT_PREFERENCES }\n}\n","import {\n\tcancel as clackCancel,\n\tconfirm as clackConfirm,\n\tintro as clackIntro,\n\tisCancel as clackIsCancel,\n\toutro as clackOutro,\n\tselect as clackSelect,\n\ttext as clackText,\n} from '@clack/prompts'\nimport { promptConfirm, promptSelect, promptText } from '../utils/prompt'\n\nexport interface SelectOption<T extends string> {\n\tlabel: string\n\tvalue: T\n\thint?: string\n\tdisabled?: boolean\n}\n\ntype ClackSelectOption<T extends string> = {\n\tvalue: T\n\tlabel?: string\n\thint?: string\n\tdisabled?: boolean\n}\n\nexport interface PromptClient {\n\ttext(message: string, defaultValue?: string): Promise<string>\n\tselect<T extends string>(message: string, options: readonly SelectOption<T>[]): Promise<T>\n\tconfirm(message: string, defaultValue?: boolean): Promise<boolean>\n\tintro(message: string): void\n\toutro(message: string): void\n}\n\nexport class PromptCancelledError extends Error {\n\tpublic constructor(message = 'Prompt cancelled by user') {\n\t\tsuper(message)\n\t\tthis.name = 'PromptCancelledError'\n\t}\n}\n\n/**\n * Prompt client backed by the current readline helpers.\n *\n * Phase 12 will introduce a richer prompt backend. This adapter keeps command\n * logic decoupled from the prompt implementation so we can migrate without\n * reshaping command behavior.\n */\nexport class ReadlinePromptClient implements PromptClient {\n\tpublic async text(message: string, defaultValue?: string): Promise<string> {\n\t\treturn promptText(message, defaultValue)\n\t}\n\n\tpublic async select<T extends string>(\n\t\tmessage: string,\n\t\toptions: readonly SelectOption<T>[],\n\t): Promise<T> {\n\t\treturn promptSelect(\n\t\t\tmessage,\n\t\t\toptions\n\t\t\t\t.filter((option) => option.disabled !== true)\n\t\t\t\t.map((option) => ({ label: option.label, value: option.value })),\n\t\t)\n\t}\n\n\tpublic async confirm(message: string, defaultValue = false): Promise<boolean> {\n\t\treturn promptConfirm(message, defaultValue)\n\t}\n\n\tpublic intro(message: string): void {\n\t\t// The readline backend does not provide intro/outro framing.\n\t\t// Keep no-op semantics for compatibility.\n\t\tvoid message\n\t}\n\n\tpublic outro(message: string): void {\n\t\t// The readline backend does not provide intro/outro framing.\n\t\t// Keep no-op semantics for compatibility.\n\t\tvoid message\n\t}\n}\n\n/**\n * Returns the default prompt client for interactive CLI flows.\n */\nexport function createPromptClient(): PromptClient {\n\tconst canUseInteractiveClack = typeof process !== 'undefined' && process.stdin.isTTY && process.stdout.isTTY\n\tif (canUseInteractiveClack) {\n\t\treturn new ClackPromptClient()\n\t}\n\treturn new ReadlinePromptClient()\n}\n\n/**\n * Prompt client backed by @clack/prompts for richer interactive UX.\n * Falls back to readline in non-interactive contexts.\n */\nexport class ClackPromptClient implements PromptClient {\n\tpublic async text(message: string, defaultValue?: string): Promise<string> {\n\t\tconst result = await clackText({\n\t\t\tmessage,\n\t\t\tplaceholder: defaultValue,\n\t\t\tdefaultValue,\n\t\t})\n\t\tif (clackIsCancel(result)) {\n\t\t\tclackCancel('Operation cancelled.')\n\t\t\tthrow new PromptCancelledError()\n\t\t}\n\t\tconst value = result.trim()\n\t\tif (value.length > 0) return value\n\t\treturn defaultValue ?? ''\n\t}\n\n\tpublic async select<T extends string>(\n\t\tmessage: string,\n\t\toptions: readonly SelectOption<T>[],\n\t): Promise<T> {\n\t\tconst mappedOptions: ClackSelectOption<T>[] = options.map((option) => ({\n\t\t\tlabel: option.label,\n\t\t\tvalue: option.value,\n\t\t\thint: option.hint,\n\t\t\tdisabled: option.disabled,\n\t\t}))\n\t\tconst result = await clackSelect({\n\t\t\tmessage,\n\t\t\toptions: mappedOptions as unknown as Parameters<typeof clackSelect>[0]['options'],\n\t\t})\n\t\tif (clackIsCancel(result)) {\n\t\t\tclackCancel('Operation cancelled.')\n\t\t\tthrow new PromptCancelledError()\n\t\t}\n\t\treturn result as T\n\t}\n\n\tpublic async confirm(message: string, defaultValue = false): Promise<boolean> {\n\t\tconst result = await clackConfirm({\n\t\t\tmessage,\n\t\t\tinitialValue: defaultValue,\n\t\t})\n\t\tif (clackIsCancel(result)) {\n\t\t\tclackCancel('Operation cancelled.')\n\t\t\tthrow new PromptCancelledError()\n\t\t}\n\t\treturn result\n\t}\n\n\tpublic intro(message: string): void {\n\t\tclackIntro(message)\n\t}\n\n\tpublic outro(message: string): void {\n\t\tclackOutro(message)\n\t}\n}\n","import { type Interface as ReadlineInterface, createInterface } from 'node:readline'\n\nexport interface PromptOptions {\n\t/** Input stream (defaults to process.stdin) */\n\tinput?: NodeJS.ReadableStream\n\t/** Output stream (defaults to process.stdout) */\n\toutput?: NodeJS.WritableStream\n}\n\n/**\n * Prompts the user for text input.\n *\n * @param message - The prompt message to display\n * @param defaultValue - Optional default value shown in brackets\n * @param options - Optional input/output streams for testing\n */\nexport function promptText(\n\tmessage: string,\n\tdefaultValue?: string,\n\toptions?: PromptOptions,\n): Promise<string> {\n\treturn new Promise((resolve) => {\n\t\tconst rl = createReadline(options)\n\t\tconst suffix = defaultValue !== undefined ? ` (${defaultValue})` : ''\n\t\trl.question(` ? ${message}${suffix}: `, (answer) => {\n\t\t\trl.close()\n\t\t\tconst trimmed = answer.trim()\n\t\t\tresolve(trimmed || defaultValue || '')\n\t\t})\n\t})\n}\n\n/**\n * Prompts the user to select from a numbered list of options.\n *\n * @param message - The prompt message to display\n * @param choices - Array of { label, value } options\n * @param options - Optional input/output streams for testing\n */\nexport function promptSelect<T extends string>(\n\tmessage: string,\n\tchoices: readonly { label: string; value: T }[],\n\toptions?: PromptOptions,\n): Promise<T> {\n\treturn new Promise((resolve) => {\n\t\tconst rl = createReadline(options)\n\t\tconst out = options?.output ?? process.stdout\n\n\t\tout.write(` ? ${message}\\n`)\n\t\tfor (let i = 0; i < choices.length; i++) {\n\t\t\tconst choice = choices[i]\n\t\t\tif (choice) {\n\t\t\t\tout.write(` ${i + 1}) ${choice.label}\\n`)\n\t\t\t}\n\t\t}\n\n\t\tconst ask = (): void => {\n\t\t\trl.question(' > ', (answer) => {\n\t\t\t\tconst index = Number.parseInt(answer.trim(), 10) - 1\n\t\t\t\tconst selected = choices[index]\n\t\t\t\tif (selected) {\n\t\t\t\t\trl.close()\n\t\t\t\t\tresolve(selected.value)\n\t\t\t\t} else {\n\t\t\t\t\tout.write(` Please enter a number between 1 and ${choices.length}\\n`)\n\t\t\t\t\task()\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\task()\n\t})\n}\n\n/**\n * Prompts the user with a yes/no confirmation.\n *\n * @param message - The prompt message to display\n * @param defaultValue - Default when input is empty (true => yes)\n * @param options - Optional input/output streams for testing\n */\nexport function promptConfirm(\n\tmessage: string,\n\tdefaultValue = false,\n\toptions?: PromptOptions,\n): Promise<boolean> {\n\treturn new Promise((resolve) => {\n\t\tconst rl = createReadline(options)\n\t\tconst suffix = defaultValue ? 'Y/n' : 'y/N'\n\n\t\tconst ask = (): void => {\n\t\t\trl.question(` ? ${message} (${suffix}): `, (answer) => {\n\t\t\t\tconst normalized = answer.trim().toLowerCase()\n\t\t\t\tif (normalized.length === 0) {\n\t\t\t\t\trl.close()\n\t\t\t\t\tresolve(defaultValue)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif (normalized === 'y' || normalized === 'yes') {\n\t\t\t\t\trl.close()\n\t\t\t\t\tresolve(true)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif (normalized === 'n' || normalized === 'no') {\n\t\t\t\t\trl.close()\n\t\t\t\t\tresolve(false)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t(options?.output ?? process.stdout).write(' Please answer with y or n\\n')\n\t\t\t\task()\n\t\t\t})\n\t\t}\n\n\t\task()\n\t})\n}\n\nfunction createReadline(options?: PromptOptions): ReadlineInterface {\n\treturn createInterface({\n\t\tinput: options?.input ?? process.stdin,\n\t\toutput: options?.output ?? process.stdout,\n\t})\n}\n","/** Supported package managers */\nexport const PACKAGE_MANAGERS = ['pnpm', 'npm', 'yarn', 'bun'] as const\nexport type PackageManager = (typeof PACKAGE_MANAGERS)[number]\n\n/** Available project templates */\nexport const TEMPLATES = [\n\t'react-tailwind-sync',\n\t'react-tailwind',\n\t'react-sync',\n\t'react-basic',\n\t'tauri-react',\n] as const\nexport type TemplateName = (typeof TEMPLATES)[number]\n\n/** Metadata for a project template */\nexport interface TemplateInfo {\n\tname: TemplateName\n\tlabel: string\n\tdescription: string\n}\n\n/** Available templates with their descriptions */\nexport const TEMPLATE_INFO: readonly TemplateInfo[] = [\n\t{\n\t\tname: 'react-tailwind-sync',\n\t\tlabel: 'React + Tailwind (with sync)',\n\t\tdescription: 'Polished dark-themed app with Tailwind CSS and sync server (Recommended)',\n\t},\n\t{\n\t\tname: 'react-tailwind',\n\t\tlabel: 'React + Tailwind (local-only)',\n\t\tdescription: 'Polished dark-themed app with Tailwind CSS — no sync server',\n\t},\n\t{\n\t\tname: 'react-sync',\n\t\tlabel: 'React + CSS (with sync)',\n\t\tdescription: 'Clean CSS app with sync server included',\n\t},\n\t{\n\t\tname: 'react-basic',\n\t\tlabel: 'React + CSS (local-only)',\n\t\tdescription: 'Clean CSS app — no sync server',\n\t},\n\t{\n\t\tname: 'tauri-react',\n\t\tlabel: 'Tauri Desktop (native SQLite)',\n\t\tdescription: 'Desktop app with native SQLite — no WASM, includes sync server',\n\t},\n] as const\n\n/** Variables available for template substitution */\nexport interface TemplateContext {\n\tprojectName: string\n\tpackageManager: PackageManager\n\tkoraVersion: string\n\tdbProvider?: string\n}\n","import type { TemplateName } from '../../types'\n\nexport type PlatformOption = 'web' | 'desktop-tauri'\nexport type FrameworkOption = 'react' | 'vue' | 'svelte' | 'solid'\nexport type AuthOption = 'none' | 'email-password' | 'oauth'\nexport type DatabaseOption = 'none' | 'sqlite' | 'postgres'\nexport type DatabaseProviderOption =\n\t| 'none'\n\t| 'local'\n\t| 'supabase'\n\t| 'neon'\n\t| 'railway'\n\t| 'vercel-postgres'\n\t| 'custom'\n\nexport interface TemplateSelectionInput {\n\tplatform: PlatformOption\n\ttailwind: boolean\n\tsync: boolean\n\tdb: DatabaseOption\n}\n\n/**\n * Converts high-level scaffold selections into the currently supported\n * concrete template names.\n */\nexport function determineTemplateFromSelections(input: TemplateSelectionInput): TemplateName {\n\tif (input.platform === 'desktop-tauri') return 'tauri-react'\n\tconst shouldSync = input.sync && input.db !== 'none'\n\tif (input.tailwind && shouldSync) return 'react-tailwind-sync'\n\tif (input.tailwind && !shouldSync) return 'react-tailwind'\n\tif (!input.tailwind && shouldSync) return 'react-sync'\n\treturn 'react-basic'\n}\n\nexport function isPlatformValue(value: string): value is PlatformOption {\n\treturn value === 'web' || value === 'desktop-tauri'\n}\n\nexport function isFrameworkValue(value: string): value is FrameworkOption {\n\treturn value === 'react' || value === 'vue' || value === 'svelte' || value === 'solid'\n}\n\nexport function isAuthValue(value: string): value is AuthOption {\n\treturn value === 'none' || value === 'email-password' || value === 'oauth'\n}\n\nexport function isDatabaseValue(value: string): value is DatabaseOption {\n\treturn value === 'none' || value === 'sqlite' || value === 'postgres'\n}\n\nexport function isDatabaseProviderValue(value: string): value is DatabaseProviderOption {\n\treturn (\n\t\tvalue === 'none' ||\n\t\tvalue === 'local' ||\n\t\tvalue === 'supabase' ||\n\t\tvalue === 'neon' ||\n\t\tvalue === 'railway' ||\n\t\tvalue === 'vercel-postgres' ||\n\t\tvalue === 'custom'\n\t)\n}\n","import type { PromptClient } from '../../prompts/prompt-client'\nimport {\n\tgetDefaultCreatePreferences,\n\tgetCreatePreferencesOrDefault,\n\ttype CreatePreferences,\n\ttype PreferenceStore,\n} from '../../prompts/preferences'\nimport {\n\tdetermineTemplateFromSelections,\n\tisAuthValue,\n\tisDatabaseProviderValue,\n\tisDatabaseValue,\n\tisFrameworkValue,\n\tisPlatformValue,\n\ttype AuthOption,\n\ttype DatabaseOption,\n\ttype DatabaseProviderOption,\n\ttype FrameworkOption,\n\ttype PlatformOption,\n} from './options'\n\nexport interface CreateFlags {\n\tplatform?: string\n\tframework?: string\n\tauth?: string\n\tdb?: string\n\tdbProvider?: string\n\ttailwind?: boolean\n\tsync?: boolean\n\tuseDefaults: boolean\n}\n\nexport interface PreferenceResolutionResult {\n\tplatform: PlatformOption\n\tframework: FrameworkOption\n\tauth: AuthOption\n\tdb: DatabaseOption\n\tdbProvider: DatabaseProviderOption\n\ttailwind: boolean\n\tsync: boolean\n\ttemplate: ReturnType<typeof determineTemplateFromSelections>\n\tusedStoredPreferences: boolean\n}\n\n/**\n * Resolves scaffold options with precedence:\n * CLI flags > --yes defaults > stored preferences > interactive prompts.\n */\nexport async function resolveCreatePreferencesFlow(params: {\n\tflags: CreateFlags\n\tprompts: PromptClient\n\tstore: PreferenceStore\n}): Promise<PreferenceResolutionResult> {\n\tconst { flags, prompts, store } = params\n\tconst stored = store.getCreatePreferences()\n\tconst base = getCreatePreferencesOrDefault(store)\n\tconst hasExplicitFlags = hasExplicitPreferenceFlags(flags)\n\tconst canOfferStored =\n\t\t!flags.useDefaults && !hasExplicitFlags && stored !== null && promptSupportsRichOptions()\n\n\tlet effective: CreatePreferences = { ...base }\n\tlet usedStoredPreferences = false\n\n\tif (flags.useDefaults) {\n\t\teffective = getDefaultCreatePreferences()\n\t} else if (canOfferStored && stored !== null) {\n\t\tconst reuseStored = await prompts.select('Welcome back! Choose setup mode:', [\n\t\t\t{ label: formatStoredPreferenceLabel(stored), value: 'reuse' },\n\t\t\t{ label: 'Customize', value: 'customize' },\n\t\t])\n\t\tif (reuseStored === 'reuse') {\n\t\t\teffective = { ...stored }\n\t\t\tusedStoredPreferences = true\n\t\t}\n\t}\n\n\tif (flags.platform !== undefined) {\n\t\tif (!isPlatformValue(flags.platform)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid --platform value \"${flags.platform}\". Expected one of: web, desktop-tauri.`,\n\t\t\t)\n\t\t}\n\t\teffective.platform = flags.platform\n\t} else if (!flags.useDefaults && !usedStoredPreferences) {\n\t\teffective.platform = await prompts.select('Platform:', [\n\t\t\t{ label: 'Web (browser)', value: 'web' },\n\t\t\t{ label: 'Desktop (Tauri — native SQLite)', value: 'desktop-tauri' },\n\t\t])\n\t}\n\n\tconst isTauri = effective.platform === 'desktop-tauri'\n\n\tif (isTauri) {\n\t\t// Tauri uses fixed settings: React, plain CSS, native SQLite\n\t\teffective.framework = 'react'\n\t\teffective.tailwind = false\n\t\teffective.sync = true\n\t\teffective.db = 'sqlite'\n\t\teffective.dbProvider = 'none'\n\t\teffective.auth = 'none'\n\t} else {\n\t\tif (flags.framework !== undefined) {\n\t\t\tif (!isFrameworkValue(flags.framework)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid --framework value \"${flags.framework}\". Expected one of: react, vue, svelte, solid.`,\n\t\t\t\t)\n\t\t\t}\n\t\t\teffective.framework = flags.framework\n\t\t} else if (!flags.useDefaults && !usedStoredPreferences) {\n\t\t\teffective.framework = await prompts.select('UI framework:', [\n\t\t\t\t{ label: 'React', value: 'react' },\n\t\t\t\t{ label: 'Vue (coming soon)', value: 'vue', disabled: true },\n\t\t\t\t{ label: 'Svelte (coming soon)', value: 'svelte', disabled: true },\n\t\t\t\t{ label: 'Solid (coming soon)', value: 'solid', disabled: true },\n\t\t\t])\n\t\t}\n\n\t\tif (flags.auth !== undefined) {\n\t\t\tif (!isAuthValue(flags.auth)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid --auth value \"${flags.auth}\". Expected one of: none, email-password, oauth.`,\n\t\t\t\t)\n\t\t\t}\n\t\t\teffective.auth = flags.auth\n\t\t} else if (!flags.useDefaults && !usedStoredPreferences) {\n\t\t\teffective.auth = await prompts.select('Authentication:', [\n\t\t\t\t{ label: 'None', value: 'none' },\n\t\t\t\t{ label: 'Email + Password (coming soon)', value: 'email-password', disabled: true },\n\t\t\t\t{ label: 'OAuth (coming soon)', value: 'oauth', disabled: true },\n\t\t\t])\n\t\t}\n\n\t\tif (flags.tailwind !== undefined) {\n\t\t\teffective.tailwind = flags.tailwind\n\t\t} else if (!flags.useDefaults && !usedStoredPreferences) {\n\t\t\teffective.tailwind = await prompts.confirm('Use Tailwind CSS?', true)\n\t\t}\n\n\t\tif (flags.sync !== undefined) {\n\t\t\teffective.sync = flags.sync\n\t\t} else if (!flags.useDefaults && !usedStoredPreferences) {\n\t\t\teffective.sync = await prompts.confirm('Enable multi-device sync?', true)\n\t\t}\n\n\t\tif (flags.db !== undefined) {\n\t\t\tif (!isDatabaseValue(flags.db)) {\n\t\t\t\tthrow new Error(`Invalid --db value \"${flags.db}\". Expected one of: none, sqlite, postgres.`)\n\t\t\t}\n\t\t\teffective.db = flags.db\n\t\t} else if (!effective.sync) {\n\t\t\teffective.db = 'none'\n\t\t} else if (!flags.useDefaults && !usedStoredPreferences) {\n\t\t\teffective.db = await prompts.select('Server-side database:', [\n\t\t\t\t{ label: 'SQLite (zero-config)', value: 'sqlite' },\n\t\t\t\t{ label: 'PostgreSQL (production-scale)', value: 'postgres' },\n\t\t\t])\n\t\t}\n\n\t\tif (effective.db !== 'postgres') {\n\t\t\teffective.dbProvider = 'none'\n\t\t} else if (flags.dbProvider !== undefined) {\n\t\t\tif (!isDatabaseProviderValue(flags.dbProvider)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid --db-provider value \"${flags.dbProvider}\". Expected one of: none, local, supabase, neon, railway, vercel-postgres, custom.`,\n\t\t\t\t)\n\t\t\t}\n\t\t\teffective.dbProvider = flags.dbProvider\n\t\t} else if (!flags.useDefaults && !usedStoredPreferences) {\n\t\t\teffective.dbProvider = await prompts.select('Database provider:', [\n\t\t\t\t{ label: 'Local Postgres', value: 'local' },\n\t\t\t\t{ label: 'Supabase', value: 'supabase' },\n\t\t\t\t{ label: 'Neon', value: 'neon' },\n\t\t\t\t{ label: 'Railway', value: 'railway' },\n\t\t\t\t{ label: 'Vercel Postgres', value: 'vercel-postgres' },\n\t\t\t\t{ label: 'Custom connection string', value: 'custom' },\n\t\t\t])\n\t\t}\n\t}\n\n\tconst template = determineTemplateFromSelections({\n\t\tplatform: effective.platform,\n\t\ttailwind: effective.tailwind,\n\t\tsync: effective.sync,\n\t\tdb: effective.db,\n\t})\n\n\treturn {\n\t\tplatform: effective.platform,\n\t\tframework: effective.framework,\n\t\tauth: effective.auth,\n\t\tdb: effective.db,\n\t\tdbProvider: effective.dbProvider,\n\t\ttailwind: effective.tailwind,\n\t\tsync: effective.sync,\n\t\ttemplate,\n\t\tusedStoredPreferences,\n\t}\n}\n\nexport function shouldSavePreferences(flags: CreateFlags): boolean {\n\treturn !flags.useDefaults\n}\n\nexport function saveResolvedPreferences(\n\tstore: PreferenceStore,\n\tresolution: Omit<PreferenceResolutionResult, 'template' | 'usedStoredPreferences'> & {\n\t\tpackageManager: CreatePreferences['packageManager']\n\t},\n): void {\n\tstore.saveCreatePreferences({\n\t\tplatform: resolution.platform,\n\t\tframework: resolution.framework,\n\t\ttailwind: resolution.tailwind,\n\t\tsync: resolution.sync,\n\t\tdb: resolution.db,\n\t\tdbProvider: resolution.dbProvider,\n\t\tauth: resolution.auth,\n\t\tpackageManager: resolution.packageManager,\n\t})\n}\n\nfunction hasExplicitPreferenceFlags(flags: CreateFlags): boolean {\n\treturn (\n\t\tflags.platform !== undefined ||\n\t\tflags.framework !== undefined ||\n\t\tflags.auth !== undefined ||\n\t\tflags.db !== undefined ||\n\t\tflags.dbProvider !== undefined ||\n\t\tflags.tailwind !== undefined ||\n\t\tflags.sync !== undefined\n\t)\n}\n\nfunction promptSupportsRichOptions(): boolean {\n\treturn typeof process !== 'undefined' && process.stdin.isTTY && process.stdout.isTTY\n}\n\nfunction formatStoredPreferenceLabel(preferences: CreatePreferences): string {\n\tif (preferences.platform === 'desktop-tauri') {\n\t\treturn `Use previous settings (tauri-desktop + ${preferences.packageManager})`\n\t}\n\tconst syncLabel = preferences.sync ? `sync/${preferences.db}` : 'local-only'\n\tconst styleLabel = preferences.tailwind ? 'tailwind' : 'css'\n\treturn `Use previous settings (${preferences.framework} + ${styleLabel} + ${syncLabel} + ${preferences.packageManager})`\n}\n","import validateNpmPackageName from 'validate-npm-package-name'\n\nexport interface ProjectNameValidationResult {\n\tvalid: boolean\n\tissues: readonly string[]\n}\n\n/**\n * Validates a project name for scaffolded package creation.\n *\n * The create command uses this validation before writing files so users get a\n * clear, early error if the name cannot be used as an npm package name.\n */\nexport function validateProjectName(name: string): ProjectNameValidationResult {\n\tconst trimmedName = name.trim()\n\tif (trimmedName.length === 0) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tissues: ['Project name cannot be empty.'],\n\t\t}\n\t}\n\n\tconst validation = validateNpmPackageName(trimmedName)\n\tconst issues = [...(validation.errors ?? []), ...(validation.warnings ?? [])]\n\tif (!validation.validForNewPackages && issues.length === 0) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tissues: ['Project name is not a valid npm package name.'],\n\t\t}\n\t}\n\n\treturn {\n\t\tvalid: validation.validForNewPackages,\n\t\tissues,\n\t}\n}\n","import { readFile, writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport type { TemplateName } from '../../types'\nimport type { DatabaseOption, DatabaseProviderOption } from './options'\n\ninterface SyncProviderPresetOptions {\n\ttargetDir: string\n\ttemplate: TemplateName\n\tdb: DatabaseOption\n\tdbProvider: DatabaseProviderOption\n}\n\n/**\n * Applies provider-specific sync scaffolding adjustments after template copy.\n *\n * This is a lightweight bridge until template-layer composition lands.\n * Today we only specialize the sync server template when Postgres is selected.\n */\nexport async function applySyncProviderPreset(options: SyncProviderPresetOptions): Promise<void> {\n\tif (!isSyncTemplate(options.template)) {\n\t\treturn\n\t}\n\tif (options.db !== 'postgres') {\n\t\treturn\n\t}\n\n\tconst providerName = getProviderDisplayName(options.dbProvider)\n\tconst providerConnectionString = getProviderConnectionStringExample(options.dbProvider)\n\tconst serverPath = join(options.targetDir, 'server.ts')\n\tconst envPath = join(options.targetDir, '.env.example')\n\tconst readmePath = join(options.targetDir, 'README.md')\n\n\tconst serverTemplate = [\n\t\t\"import { createPostgresServerStore, createProductionServer } from '@korajs/server'\",\n\t\t'',\n\t\t`// PostgreSQL provider preset: ${providerName}`,\n\t\t'// Ensure DATABASE_URL is set in your environment.',\n\t\t'',\n\t\t'async function start(): Promise<void> {',\n\t\t\"\\tconst connectionString = process.env.DATABASE_URL || ''\",\n\t\t'\\tif (connectionString.length === 0) {',\n\t\t\"\\t\\tthrow new Error('DATABASE_URL is required for PostgreSQL sync server store.')\",\n\t\t'\\t}',\n\t\t'',\n\t\t'\\tconst store = await createPostgresServerStore({ connectionString })',\n\t\t'\\tconst server = createProductionServer({',\n\t\t'\\t\\tstore,',\n\t\t\"\\t\\tport: Number(process.env.PORT) || 3001,\",\n\t\t\"\\t\\tstaticDir: './dist',\",\n\t\t\"\\t\\tsyncPath: '/kora-sync',\",\n\t\t'\\t})',\n\t\t'',\n\t\t'\\tconst url = await server.start()',\n\t\t'\\tconsole.log(`Kora app running at ${url}`)',\n\t\t'}',\n\t\t'',\n\t\t'void start()',\n\t\t'',\n\t].join('\\n')\n\n\tconst envTemplate = [\n\t\t'# Kora Sync Server',\n\t\t'# WebSocket URL for the sync server (used by the client)',\n\t\t'VITE_SYNC_URL=ws://localhost:3001',\n\t\t'',\n\t\t'# Sync server port',\n\t\t'PORT=3001',\n\t\t'',\n\t\t`# PostgreSQL connection string (${providerName})`,\n\t\t`# Example: ${providerConnectionString}`,\n\t\t'DATABASE_URL=',\n\t\t'',\n\t].join('\\n')\n\n\tconst existingReadme = await readFile(readmePath, 'utf-8')\n\tconst trimmedReadme = existingReadme.trimEnd()\n\tconst readmeSuffix = [\n\t\t'',\n\t\t'## PostgreSQL Provider Preset',\n\t\t'',\n\t\t`Selected DB provider: ${options.dbProvider}`,\n\t\t'',\n\t\t'This scaffold uses `createPostgresServerStore` in `server.ts` and reads `DATABASE_URL` from the environment. See `.env.example` for provider-specific examples.',\n\t\t'',\n\t].join('\\n')\n\tconst readmeTemplate = `${trimmedReadme}${readmeSuffix}`\n\n\tawait writeFile(serverPath, serverTemplate, 'utf-8')\n\tawait writeFile(envPath, envTemplate, 'utf-8')\n\tawait writeFile(readmePath, readmeTemplate, 'utf-8')\n}\n\nfunction isSyncTemplate(template: TemplateName): boolean {\n\treturn template === 'react-sync' || template === 'react-tailwind-sync' || template === 'tauri-react'\n}\n\nfunction getProviderDisplayName(provider: DatabaseProviderOption): string {\n\tswitch (provider) {\n\t\tcase 'supabase':\n\t\t\treturn 'Supabase'\n\t\tcase 'neon':\n\t\t\treturn 'Neon'\n\t\tcase 'railway':\n\t\t\treturn 'Railway'\n\t\tcase 'vercel-postgres':\n\t\t\treturn 'Vercel Postgres'\n\t\tcase 'custom':\n\t\t\treturn 'Custom'\n\t\tcase 'local':\n\t\t\treturn 'Local Postgres'\n\t\tcase 'none':\n\t\t\treturn 'PostgreSQL'\n\t}\n}\n\nfunction getProviderConnectionStringExample(provider: DatabaseProviderOption): string {\n\tswitch (provider) {\n\t\tcase 'supabase':\n\t\t\treturn 'postgresql://postgres:<password>@db.<project-ref>.supabase.co:5432/postgres?sslmode=require'\n\t\tcase 'neon':\n\t\t\treturn 'postgresql://<user>:<password>@<branch>.<project>.neon.tech/neondb?sslmode=require'\n\t\tcase 'railway':\n\t\t\treturn 'postgresql://postgres:<password>@<host>.railway.app:<port>/railway?sslmode=require'\n\t\tcase 'vercel-postgres':\n\t\t\treturn 'postgresql://<user>:<password>@<host>.pooler.vercel-storage.com:5432/verceldb?sslmode=require'\n\t\tcase 'custom':\n\t\t\treturn 'postgresql://<user>:<password>@<host>:5432/<database>'\n\t\tcase 'local':\n\t\t\treturn 'postgresql://postgres:postgres@localhost:5432/kora'\n\t\tcase 'none':\n\t\t\treturn 'postgresql://postgres:postgres@localhost:5432/kora'\n\t}\n}\n","import { access, readFile } from 'node:fs/promises'\nimport { dirname, join, resolve } from 'node:path'\n\n/** Checks if a directory exists at the given path */\nexport async function directoryExists(path: string): Promise<boolean> {\n\ttry {\n\t\tawait access(path)\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/**\n * Walks up the directory tree from startDir looking for a package.json\n * that contains a kora or @korajs/* dependency.\n *\n * @param startDir - Directory to start searching from (defaults to cwd)\n * @returns Absolute path to the project root, or null if not found\n */\nexport async function findProjectRoot(startDir?: string): Promise<string | null> {\n\tlet current = resolve(startDir ?? process.cwd())\n\n\t// Walk up until the filesystem root (where dirname(x) === x)\n\tfor (;;) {\n\t\tconst pkgPath = join(current, 'package.json')\n\t\ttry {\n\t\t\tconst content = await readFile(pkgPath, 'utf-8')\n\t\t\tconst pkg: unknown = JSON.parse(content)\n\t\t\tif (isKoraProject(pkg)) {\n\t\t\t\treturn current\n\t\t\t}\n\t\t} catch {\n\t\t\t// No package.json at this level, keep walking up\n\t\t}\n\t\tconst parent = dirname(current)\n\t\tif (parent === current) break\n\t\tcurrent = parent\n\t}\n\n\treturn null\n}\n\n/**\n * Searches for a schema file in common locations within a project.\n *\n * @param projectRoot - The project root directory\n * @returns Absolute path to the schema file, or null if not found\n */\nexport async function findSchemaFile(projectRoot: string): Promise<string | null> {\n\tconst candidates = [\n\t\tjoin(projectRoot, 'src', 'schema.ts'),\n\t\tjoin(projectRoot, 'schema.ts'),\n\t\tjoin(projectRoot, 'src', 'schema.js'),\n\t\tjoin(projectRoot, 'schema.js'),\n\t]\n\n\tfor (const candidate of candidates) {\n\t\ttry {\n\t\t\tawait access(candidate)\n\t\t\treturn candidate\n\t\t} catch {\n\t\t\t// Not found, try next\n\t\t}\n\t}\n\n\treturn null\n}\n\n/**\n * Resolves a binary from a project's local node_modules/.bin directory.\n * On Windows, npm creates .cmd shims instead of extensionless files.\n *\n * @param projectRoot - The project root directory\n * @param binaryName - Binary filename (for example: vite, tsx, kora)\n * @returns Absolute path to the binary, or null if not found\n */\nexport async function resolveProjectBinary(\n\tprojectRoot: string,\n\tbinaryName: string,\n): Promise<string | null> {\n\tconst binDir = join(projectRoot, 'node_modules', '.bin')\n\t// On Windows, try .cmd first (npm/pnpm create .cmd shims)\n\tconst candidates =\n\t\tprocess.platform === 'win32'\n\t\t\t? [join(binDir, `${binaryName}.cmd`), join(binDir, binaryName)]\n\t\t\t: [join(binDir, binaryName)]\n\n\tfor (const candidate of candidates) {\n\t\ttry {\n\t\t\tawait access(candidate)\n\t\t\treturn candidate\n\t\t} catch {\n\t\t\t// continue\n\t\t}\n\t}\n\treturn null\n}\n\n/**\n * Checks whether the `tsx` package is installed in the project's node_modules.\n * Used to determine if we can use `--import tsx` with process.execPath.\n */\nexport async function hasTsxInstalled(projectRoot: string): Promise<boolean> {\n\ttry {\n\t\tawait access(join(projectRoot, 'node_modules', 'tsx', 'package.json'))\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/**\n * Resolves the JS entry point for a package binary.\n * Reads the package.json bin field to find the actual JS file,\n * avoiding .cmd shims and shell:true on Windows.\n *\n * @returns Absolute path to the JS entry point, or null if not found\n */\nexport async function resolveProjectBinaryEntryPoint(\n\tprojectRoot: string,\n\tpackageName: string,\n\tbinaryName: string,\n): Promise<string | null> {\n\tconst pkgJsonPath = join(projectRoot, 'node_modules', packageName, 'package.json')\n\ttry {\n\t\tconst content = await readFile(pkgJsonPath, 'utf-8')\n\t\tconst pkg = JSON.parse(content) as { bin?: string | Record<string, string> }\n\t\tlet binPath: string | undefined\n\t\tif (typeof pkg.bin === 'string') {\n\t\t\tbinPath = pkg.bin\n\t\t} else if (typeof pkg.bin === 'object' && pkg.bin !== null) {\n\t\t\tbinPath = pkg.bin[binaryName]\n\t\t}\n\t\tif (!binPath) return null\n\t\tconst fullPath = join(projectRoot, 'node_modules', packageName, binPath)\n\t\tawait access(fullPath)\n\t\treturn fullPath\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction isKoraProject(pkg: unknown): boolean {\n\tif (typeof pkg !== 'object' || pkg === null) return false\n\tconst record = pkg as Record<string, unknown>\n\treturn hasKoraDep(record.dependencies) || hasKoraDep(record.devDependencies)\n}\n\nfunction hasKoraDep(deps: unknown): boolean {\n\tif (typeof deps !== 'object' || deps === null) return false\n\treturn Object.keys(deps).some((key) => key === 'kora' || key.startsWith('@korajs/'))\n}\n","/** ANSI escape codes for terminal colors */\nconst RESET = '\\x1b[0m'\nconst BOLD = '\\x1b[1m'\nconst DIM = '\\x1b[2m'\nconst GREEN = '\\x1b[32m'\nconst YELLOW = '\\x1b[33m'\nconst RED = '\\x1b[31m'\nconst CYAN = '\\x1b[36m'\n\nexport interface LoggerOptions {\n\t/** Disable ANSI colors */\n\tnoColor?: boolean\n}\n\nexport interface Logger {\n\tinfo(message: string): void\n\tsuccess(message: string): void\n\twarn(message: string): void\n\terror(message: string): void\n\tstep(message: string): void\n\tblank(): void\n\tbanner(): void\n}\n\n/**\n * Creates a logger with optional ANSI color support.\n * Respects the NO_COLOR environment variable and TTY detection.\n */\nexport function createLogger(options?: LoggerOptions): Logger {\n\tconst colorDisabled =\n\t\toptions?.noColor === true || process.env.NO_COLOR !== undefined || !process.stdout.isTTY\n\n\tfunction color(code: string, text: string): string {\n\t\treturn colorDisabled ? text : `${code}${text}${RESET}`\n\t}\n\n\treturn {\n\t\tinfo(message: string): void {\n\t\t\tconsole.log(color(CYAN, message))\n\t\t},\n\t\tsuccess(message: string): void {\n\t\t\tconsole.log(color(GREEN, ` ✓ ${message}`))\n\t\t},\n\t\twarn(message: string): void {\n\t\t\tconsole.warn(color(YELLOW, ` ⚠ ${message}`))\n\t\t},\n\t\terror(message: string): void {\n\t\t\tconsole.error(color(RED, ` ✗ ${message}`))\n\t\t},\n\t\tstep(message: string): void {\n\t\t\tconsole.log(color(DIM, ` ${message}`))\n\t\t},\n\t\tblank(): void {\n\t\t\tconsole.log()\n\t\t},\n\t\tbanner(): void {\n\t\t\tconsole.log()\n\t\t\tconsole.log(\n\t\t\t\tcolor(BOLD + CYAN, ' Kora.js') + color(DIM, ' — Offline-first application framework'),\n\t\t\t)\n\t\t\tconsole.log()\n\t\t},\n\t}\n}\n"],"mappings":";;;AAAA,SAAS,iBAAiB;AAKnB,IAAM,WAAN,cAAuB,UAAU;AAAA,EACvC,YAAY,SAAiB,SAAmC;AAC/D,UAAM,SAAS,aAAa,OAAO;AACnC,SAAK,OAAO;AAAA,EACb;AACD;AAKO,IAAM,qBAAN,cAAiC,UAAU;AAAA,EACjD,YAA4B,WAAmB;AAC9C;AAAA,MACC,cAAc,SAAS;AAAA,MACvB;AAAA,MACA,EAAE,UAAU;AAAA,IACb;AAL2B;AAM3B,SAAK,OAAO;AAAA,EACb;AAAA,EAP4B;AAQ7B;AAKO,IAAM,sBAAN,cAAkC,UAAU;AAAA,EAClD,YAA4B,eAAyB;AACpD;AAAA,MACC,2CAA2C,cAAc,KAAK,IAAI,CAAC;AAAA,MACnE;AAAA,MACA,EAAE,cAAc;AAAA,IACjB;AAL2B;AAM3B,SAAK,OAAO;AAAA,EACb;AAAA,EAP4B;AAQ7B;AAKO,IAAM,sBAAN,cAAkC,UAAU;AAAA,EAClD,YAA4B,WAAmB;AAC9C;AAAA,MACC,IAAI,SAAS;AAAA,MACb;AAAA,MACA,EAAE,UAAU;AAAA,IACb;AAL2B;AAM3B,SAAK,OAAO;AAAA,EACb;AAAA,EAP4B;AAQ7B;AAKO,IAAM,iBAAN,cAA6B,UAAU;AAAA,EAC7C,YACiB,QACA,YACf;AACD;AAAA,MACC,mCAAmC,MAAM,QAAQ,UAAU;AAAA,MAC3D;AAAA,MACA,EAAE,QAAQ,WAAW;AAAA,IACtB;AAPgB;AACA;AAOhB,SAAK,OAAO;AAAA,EACb;AAAA,EATiB;AAAA,EACA;AASlB;;;ACrEA,OAAO,UAAU;AAejB,IAAM,sBAAyC;AAAA,EAC9C,UAAU;AAAA,EACV,WAAW;AAAA,EACX,UAAU;AAAA,EACV,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,gBAAgB;AACjB;AAEA,IAAM,kBAAkB;AAKjB,IAAM,kBAAN,MAAsB;AAAA,EACX;AAAA,EAEV,cAAc;AACpB,SAAK,QAAQ,IAAI,KAAgD;AAAA,MAChE,aAAa;AAAA,IACd,CAAC;AAAA,EACF;AAAA,EAEO,uBAAiD;AACvD,WAAO,KAAK,MAAM,IAAI,eAAe,KAAK;AAAA,EAC3C;AAAA,EAEO,sBAAsB,aAAsC;AAClE,SAAK,MAAM,IAAI,iBAAiB,WAAW;AAAA,EAC5C;AAAA,EAEO,yBAA+B;AACrC,SAAK,MAAM,OAAO,eAAe;AAAA,EAClC;AACD;AAKO,SAAS,8BAA8B,OAA2C;AACxF,SAAO,MAAM,qBAAqB,KAAK;AACxC;AAEO,SAAS,8BAAiD;AAChE,SAAO,EAAE,GAAG,oBAAoB;AACjC;;;AC9DA;AAAA,EACC,UAAU;AAAA,EACV,WAAW;AAAA,EACX,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,UAAU;AAAA,EACV,QAAQ;AAAA,OACF;;;ACRP,SAA8C,uBAAuB;AAgB9D,SAAS,WACf,SACA,cACA,SACkB;AAClB,SAAO,IAAI,QAAQ,CAACA,aAAY;AAC/B,UAAM,KAAK,eAAe,OAAO;AACjC,UAAM,SAAS,iBAAiB,SAAY,KAAK,YAAY,MAAM;AACnE,OAAG,SAAS,OAAO,OAAO,GAAG,MAAM,MAAM,CAAC,WAAW;AACpD,SAAG,MAAM;AACT,YAAM,UAAU,OAAO,KAAK;AAC5B,MAAAA,SAAQ,WAAW,gBAAgB,EAAE;AAAA,IACtC,CAAC;AAAA,EACF,CAAC;AACF;AASO,SAAS,aACf,SACA,SACA,SACa;AACb,SAAO,IAAI,QAAQ,CAACA,aAAY;AAC/B,UAAM,KAAK,eAAe,OAAO;AACjC,UAAM,MAAM,SAAS,UAAU,QAAQ;AAEvC,QAAI,MAAM,OAAO,OAAO;AAAA,CAAI;AAC5B,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACxC,YAAM,SAAS,QAAQ,CAAC;AACxB,UAAI,QAAQ;AACX,YAAI,MAAM,OAAO,IAAI,CAAC,KAAK,OAAO,KAAK;AAAA,CAAI;AAAA,MAC5C;AAAA,IACD;AAEA,UAAM,MAAM,MAAY;AACvB,SAAG,SAAS,QAAQ,CAAC,WAAW;AAC/B,cAAM,QAAQ,OAAO,SAAS,OAAO,KAAK,GAAG,EAAE,IAAI;AACnD,cAAM,WAAW,QAAQ,KAAK;AAC9B,YAAI,UAAU;AACb,aAAG,MAAM;AACT,UAAAA,SAAQ,SAAS,KAAK;AAAA,QACvB,OAAO;AACN,cAAI,MAAM,yCAAyC,QAAQ,MAAM;AAAA,CAAI;AACrE,cAAI;AAAA,QACL;AAAA,MACD,CAAC;AAAA,IACF;AAEA,QAAI;AAAA,EACL,CAAC;AACF;AASO,SAAS,cACf,SACA,eAAe,OACf,SACmB;AACnB,SAAO,IAAI,QAAQ,CAACA,aAAY;AAC/B,UAAM,KAAK,eAAe,OAAO;AACjC,UAAM,SAAS,eAAe,QAAQ;AAEtC,UAAM,MAAM,MAAY;AACvB,SAAG,SAAS,OAAO,OAAO,KAAK,MAAM,OAAO,CAAC,WAAW;AACvD,cAAM,aAAa,OAAO,KAAK,EAAE,YAAY;AAC7C,YAAI,WAAW,WAAW,GAAG;AAC5B,aAAG,MAAM;AACT,UAAAA,SAAQ,YAAY;AACpB;AAAA,QACD;AAEA,YAAI,eAAe,OAAO,eAAe,OAAO;AAC/C,aAAG,MAAM;AACT,UAAAA,SAAQ,IAAI;AACZ;AAAA,QACD;AAEA,YAAI,eAAe,OAAO,eAAe,MAAM;AAC9C,aAAG,MAAM;AACT,UAAAA,SAAQ,KAAK;AACb;AAAA,QACD;AAEA,SAAC,SAAS,UAAU,QAAQ,QAAQ,MAAM,+BAA+B;AACzE,YAAI;AAAA,MACL,CAAC;AAAA,IACF;AAEA,QAAI;AAAA,EACL,CAAC;AACF;AAEA,SAAS,eAAe,SAA4C;AACnE,SAAO,gBAAgB;AAAA,IACtB,OAAO,SAAS,SAAS,QAAQ;AAAA,IACjC,QAAQ,SAAS,UAAU,QAAQ;AAAA,EACpC,CAAC;AACF;;;AD5FO,IAAM,uBAAN,cAAmC,MAAM;AAAA,EACxC,YAAY,UAAU,4BAA4B;AACxD,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACb;AACD;AASO,IAAM,uBAAN,MAAmD;AAAA,EACzD,MAAa,KAAK,SAAiB,cAAwC;AAC1E,WAAO,WAAW,SAAS,YAAY;AAAA,EACxC;AAAA,EAEA,MAAa,OACZ,SACA,SACa;AACb,WAAO;AAAA,MACN;AAAA,MACA,QACE,OAAO,CAAC,WAAW,OAAO,aAAa,IAAI,EAC3C,IAAI,CAAC,YAAY,EAAE,OAAO,OAAO,OAAO,OAAO,OAAO,MAAM,EAAE;AAAA,IACjE;AAAA,EACD;AAAA,EAEA,MAAa,QAAQ,SAAiB,eAAe,OAAyB;AAC7E,WAAO,cAAc,SAAS,YAAY;AAAA,EAC3C;AAAA,EAEO,MAAM,SAAuB;AAGnC,SAAK;AAAA,EACN;AAAA,EAEO,MAAM,SAAuB;AAGnC,SAAK;AAAA,EACN;AACD;AAKO,SAAS,qBAAmC;AAClD,QAAM,yBAAyB,OAAO,YAAY,eAAe,QAAQ,MAAM,SAAS,QAAQ,OAAO;AACvG,MAAI,wBAAwB;AAC3B,WAAO,IAAI,kBAAkB;AAAA,EAC9B;AACA,SAAO,IAAI,qBAAqB;AACjC;AAMO,IAAM,oBAAN,MAAgD;AAAA,EACtD,MAAa,KAAK,SAAiB,cAAwC;AAC1E,UAAM,SAAS,MAAM,UAAU;AAAA,MAC9B;AAAA,MACA,aAAa;AAAA,MACb;AAAA,IACD,CAAC;AACD,QAAI,cAAc,MAAM,GAAG;AAC1B,kBAAY,sBAAsB;AAClC,YAAM,IAAI,qBAAqB;AAAA,IAChC;AACA,UAAM,QAAQ,OAAO,KAAK;AAC1B,QAAI,MAAM,SAAS,EAAG,QAAO;AAC7B,WAAO,gBAAgB;AAAA,EACxB;AAAA,EAEA,MAAa,OACZ,SACA,SACa;AACb,UAAM,gBAAwC,QAAQ,IAAI,CAAC,YAAY;AAAA,MACtE,OAAO,OAAO;AAAA,MACd,OAAO,OAAO;AAAA,MACd,MAAM,OAAO;AAAA,MACb,UAAU,OAAO;AAAA,IAClB,EAAE;AACF,UAAM,SAAS,MAAM,YAAY;AAAA,MAChC;AAAA,MACA,SAAS;AAAA,IACV,CAAC;AACD,QAAI,cAAc,MAAM,GAAG;AAC1B,kBAAY,sBAAsB;AAClC,YAAM,IAAI,qBAAqB;AAAA,IAChC;AACA,WAAO;AAAA,EACR;AAAA,EAEA,MAAa,QAAQ,SAAiB,eAAe,OAAyB;AAC7E,UAAM,SAAS,MAAM,aAAa;AAAA,MACjC;AAAA,MACA,cAAc;AAAA,IACf,CAAC;AACD,QAAI,cAAc,MAAM,GAAG;AAC1B,kBAAY,sBAAsB;AAClC,YAAM,IAAI,qBAAqB;AAAA,IAChC;AACA,WAAO;AAAA,EACR;AAAA,EAEO,MAAM,SAAuB;AACnC,eAAW,OAAO;AAAA,EACnB;AAAA,EAEO,MAAM,SAAuB;AACnC,eAAW,OAAO;AAAA,EACnB;AACD;;;AEvJO,IAAM,mBAAmB,CAAC,QAAQ,OAAO,QAAQ,KAAK;AAItD,IAAM,YAAY;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAWO,IAAM,gBAAyC;AAAA,EACrD;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACd;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACd;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACd;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACd;AAAA,EACA;AAAA,IACC,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,EACd;AACD;;;ACtBO,SAAS,gCAAgC,OAA6C;AAC5F,MAAI,MAAM,aAAa,gBAAiB,QAAO;AAC/C,QAAM,aAAa,MAAM,QAAQ,MAAM,OAAO;AAC9C,MAAI,MAAM,YAAY,WAAY,QAAO;AACzC,MAAI,MAAM,YAAY,CAAC,WAAY,QAAO;AAC1C,MAAI,CAAC,MAAM,YAAY,WAAY,QAAO;AAC1C,SAAO;AACR;AAEO,SAAS,gBAAgB,OAAwC;AACvE,SAAO,UAAU,SAAS,UAAU;AACrC;AAEO,SAAS,iBAAiB,OAAyC;AACzE,SAAO,UAAU,WAAW,UAAU,SAAS,UAAU,YAAY,UAAU;AAChF;AAEO,SAAS,YAAY,OAAoC;AAC/D,SAAO,UAAU,UAAU,UAAU,oBAAoB,UAAU;AACpE;AAEO,SAAS,gBAAgB,OAAwC;AACvE,SAAO,UAAU,UAAU,UAAU,YAAY,UAAU;AAC5D;AAEO,SAAS,wBAAwB,OAAgD;AACvF,SACC,UAAU,UACV,UAAU,WACV,UAAU,cACV,UAAU,UACV,UAAU,aACV,UAAU,qBACV,UAAU;AAEZ;;;ACbA,eAAsB,6BAA6B,QAIX;AACvC,QAAM,EAAE,OAAO,SAAS,MAAM,IAAI;AAClC,QAAM,SAAS,MAAM,qBAAqB;AAC1C,QAAM,OAAO,8BAA8B,KAAK;AAChD,QAAM,mBAAmB,2BAA2B,KAAK;AACzD,QAAM,iBACL,CAAC,MAAM,eAAe,CAAC,oBAAoB,WAAW,QAAQ,0BAA0B;AAEzF,MAAI,YAA+B,EAAE,GAAG,KAAK;AAC7C,MAAI,wBAAwB;AAE5B,MAAI,MAAM,aAAa;AACtB,gBAAY,4BAA4B;AAAA,EACzC,WAAW,kBAAkB,WAAW,MAAM;AAC7C,UAAM,cAAc,MAAM,QAAQ,OAAO,oCAAoC;AAAA,MAC5E,EAAE,OAAO,4BAA4B,MAAM,GAAG,OAAO,QAAQ;AAAA,MAC7D,EAAE,OAAO,aAAa,OAAO,YAAY;AAAA,IAC1C,CAAC;AACD,QAAI,gBAAgB,SAAS;AAC5B,kBAAY,EAAE,GAAG,OAAO;AACxB,8BAAwB;AAAA,IACzB;AAAA,EACD;AAEA,MAAI,MAAM,aAAa,QAAW;AACjC,QAAI,CAAC,gBAAgB,MAAM,QAAQ,GAAG;AACrC,YAAM,IAAI;AAAA,QACT,6BAA6B,MAAM,QAAQ;AAAA,MAC5C;AAAA,IACD;AACA,cAAU,WAAW,MAAM;AAAA,EAC5B,WAAW,CAAC,MAAM,eAAe,CAAC,uBAAuB;AACxD,cAAU,WAAW,MAAM,QAAQ,OAAO,aAAa;AAAA,MACtD,EAAE,OAAO,iBAAiB,OAAO,MAAM;AAAA,MACvC,EAAE,OAAO,wCAAmC,OAAO,gBAAgB;AAAA,IACpE,CAAC;AAAA,EACF;AAEA,QAAM,UAAU,UAAU,aAAa;AAEvC,MAAI,SAAS;AAEZ,cAAU,YAAY;AACtB,cAAU,WAAW;AACrB,cAAU,OAAO;AACjB,cAAU,KAAK;AACf,cAAU,aAAa;AACvB,cAAU,OAAO;AAAA,EAClB,OAAO;AACN,QAAI,MAAM,cAAc,QAAW;AAClC,UAAI,CAAC,iBAAiB,MAAM,SAAS,GAAG;AACvC,cAAM,IAAI;AAAA,UACT,8BAA8B,MAAM,SAAS;AAAA,QAC9C;AAAA,MACD;AACA,gBAAU,YAAY,MAAM;AAAA,IAC7B,WAAW,CAAC,MAAM,eAAe,CAAC,uBAAuB;AACxD,gBAAU,YAAY,MAAM,QAAQ,OAAO,iBAAiB;AAAA,QAC3D,EAAE,OAAO,SAAS,OAAO,QAAQ;AAAA,QACjC,EAAE,OAAO,qBAAqB,OAAO,OAAO,UAAU,KAAK;AAAA,QAC3D,EAAE,OAAO,wBAAwB,OAAO,UAAU,UAAU,KAAK;AAAA,QACjE,EAAE,OAAO,uBAAuB,OAAO,SAAS,UAAU,KAAK;AAAA,MAChE,CAAC;AAAA,IACF;AAEA,QAAI,MAAM,SAAS,QAAW;AAC7B,UAAI,CAAC,YAAY,MAAM,IAAI,GAAG;AAC7B,cAAM,IAAI;AAAA,UACT,yBAAyB,MAAM,IAAI;AAAA,QACpC;AAAA,MACD;AACA,gBAAU,OAAO,MAAM;AAAA,IACxB,WAAW,CAAC,MAAM,eAAe,CAAC,uBAAuB;AACxD,gBAAU,OAAO,MAAM,QAAQ,OAAO,mBAAmB;AAAA,QACxD,EAAE,OAAO,QAAQ,OAAO,OAAO;AAAA,QAC/B,EAAE,OAAO,kCAAkC,OAAO,kBAAkB,UAAU,KAAK;AAAA,QACnF,EAAE,OAAO,uBAAuB,OAAO,SAAS,UAAU,KAAK;AAAA,MAChE,CAAC;AAAA,IACF;AAEA,QAAI,MAAM,aAAa,QAAW;AACjC,gBAAU,WAAW,MAAM;AAAA,IAC5B,WAAW,CAAC,MAAM,eAAe,CAAC,uBAAuB;AACxD,gBAAU,WAAW,MAAM,QAAQ,QAAQ,qBAAqB,IAAI;AAAA,IACrE;AAEA,QAAI,MAAM,SAAS,QAAW;AAC7B,gBAAU,OAAO,MAAM;AAAA,IACxB,WAAW,CAAC,MAAM,eAAe,CAAC,uBAAuB;AACxD,gBAAU,OAAO,MAAM,QAAQ,QAAQ,6BAA6B,IAAI;AAAA,IACzE;AAEA,QAAI,MAAM,OAAO,QAAW;AAC3B,UAAI,CAAC,gBAAgB,MAAM,EAAE,GAAG;AAC/B,cAAM,IAAI,MAAM,uBAAuB,MAAM,EAAE,6CAA6C;AAAA,MAC7F;AACA,gBAAU,KAAK,MAAM;AAAA,IACtB,WAAW,CAAC,UAAU,MAAM;AAC3B,gBAAU,KAAK;AAAA,IAChB,WAAW,CAAC,MAAM,eAAe,CAAC,uBAAuB;AACxD,gBAAU,KAAK,MAAM,QAAQ,OAAO,yBAAyB;AAAA,QAC5D,EAAE,OAAO,wBAAwB,OAAO,SAAS;AAAA,QACjD,EAAE,OAAO,iCAAiC,OAAO,WAAW;AAAA,MAC7D,CAAC;AAAA,IACF;AAEA,QAAI,UAAU,OAAO,YAAY;AAChC,gBAAU,aAAa;AAAA,IACxB,WAAW,MAAM,eAAe,QAAW;AAC1C,UAAI,CAAC,wBAAwB,MAAM,UAAU,GAAG;AAC/C,cAAM,IAAI;AAAA,UACT,gCAAgC,MAAM,UAAU;AAAA,QACjD;AAAA,MACD;AACA,gBAAU,aAAa,MAAM;AAAA,IAC9B,WAAW,CAAC,MAAM,eAAe,CAAC,uBAAuB;AACxD,gBAAU,aAAa,MAAM,QAAQ,OAAO,sBAAsB;AAAA,QACjE,EAAE,OAAO,kBAAkB,OAAO,QAAQ;AAAA,QAC1C,EAAE,OAAO,YAAY,OAAO,WAAW;AAAA,QACvC,EAAE,OAAO,QAAQ,OAAO,OAAO;AAAA,QAC/B,EAAE,OAAO,WAAW,OAAO,UAAU;AAAA,QACrC,EAAE,OAAO,mBAAmB,OAAO,kBAAkB;AAAA,QACrD,EAAE,OAAO,4BAA4B,OAAO,SAAS;AAAA,MACtD,CAAC;AAAA,IACF;AAAA,EACD;AAEA,QAAM,WAAW,gCAAgC;AAAA,IAChD,UAAU,UAAU;AAAA,IACpB,UAAU,UAAU;AAAA,IACpB,MAAM,UAAU;AAAA,IAChB,IAAI,UAAU;AAAA,EACf,CAAC;AAED,SAAO;AAAA,IACN,UAAU,UAAU;AAAA,IACpB,WAAW,UAAU;AAAA,IACrB,MAAM,UAAU;AAAA,IAChB,IAAI,UAAU;AAAA,IACd,YAAY,UAAU;AAAA,IACtB,UAAU,UAAU;AAAA,IACpB,MAAM,UAAU;AAAA,IAChB;AAAA,IACA;AAAA,EACD;AACD;AAEO,SAAS,sBAAsB,OAA6B;AAClE,SAAO,CAAC,MAAM;AACf;AAEO,SAAS,wBACf,OACA,YAGO;AACP,QAAM,sBAAsB;AAAA,IAC3B,UAAU,WAAW;AAAA,IACrB,WAAW,WAAW;AAAA,IACtB,UAAU,WAAW;AAAA,IACrB,MAAM,WAAW;AAAA,IACjB,IAAI,WAAW;AAAA,IACf,YAAY,WAAW;AAAA,IACvB,MAAM,WAAW;AAAA,IACjB,gBAAgB,WAAW;AAAA,EAC5B,CAAC;AACF;AAEA,SAAS,2BAA2B,OAA6B;AAChE,SACC,MAAM,aAAa,UACnB,MAAM,cAAc,UACpB,MAAM,SAAS,UACf,MAAM,OAAO,UACb,MAAM,eAAe,UACrB,MAAM,aAAa,UACnB,MAAM,SAAS;AAEjB;AAEA,SAAS,4BAAqC;AAC7C,SAAO,OAAO,YAAY,eAAe,QAAQ,MAAM,SAAS,QAAQ,OAAO;AAChF;AAEA,SAAS,4BAA4B,aAAwC;AAC5E,MAAI,YAAY,aAAa,iBAAiB;AAC7C,WAAO,0CAA0C,YAAY,cAAc;AAAA,EAC5E;AACA,QAAM,YAAY,YAAY,OAAO,QAAQ,YAAY,EAAE,KAAK;AAChE,QAAM,aAAa,YAAY,WAAW,aAAa;AACvD,SAAO,0BAA0B,YAAY,SAAS,MAAM,UAAU,MAAM,SAAS,MAAM,YAAY,cAAc;AACtH;;;ACpPA,OAAO,4BAA4B;AAa5B,SAAS,oBAAoB,MAA2C;AAC9E,QAAM,cAAc,KAAK,KAAK;AAC9B,MAAI,YAAY,WAAW,GAAG;AAC7B,WAAO;AAAA,MACN,OAAO;AAAA,MACP,QAAQ,CAAC,+BAA+B;AAAA,IACzC;AAAA,EACD;AAEA,QAAM,aAAa,uBAAuB,WAAW;AACrD,QAAM,SAAS,CAAC,GAAI,WAAW,UAAU,CAAC,GAAI,GAAI,WAAW,YAAY,CAAC,CAAE;AAC5E,MAAI,CAAC,WAAW,uBAAuB,OAAO,WAAW,GAAG;AAC3D,WAAO;AAAA,MACN,OAAO;AAAA,MACP,QAAQ,CAAC,+CAA+C;AAAA,IACzD;AAAA,EACD;AAEA,SAAO;AAAA,IACN,OAAO,WAAW;AAAA,IAClB;AAAA,EACD;AACD;;;ACnCA,SAAS,UAAU,iBAAiB;AACpC,SAAS,YAAY;AAiBrB,eAAsB,wBAAwB,SAAmD;AAChG,MAAI,CAAC,eAAe,QAAQ,QAAQ,GAAG;AACtC;AAAA,EACD;AACA,MAAI,QAAQ,OAAO,YAAY;AAC9B;AAAA,EACD;AAEA,QAAM,eAAe,uBAAuB,QAAQ,UAAU;AAC9D,QAAM,2BAA2B,mCAAmC,QAAQ,UAAU;AACtF,QAAM,aAAa,KAAK,QAAQ,WAAW,WAAW;AACtD,QAAM,UAAU,KAAK,QAAQ,WAAW,cAAc;AACtD,QAAM,aAAa,KAAK,QAAQ,WAAW,WAAW;AAEtD,QAAM,iBAAiB;AAAA,IACtB;AAAA,IACA;AAAA,IACA,kCAAkC,YAAY;AAAA,IAC9C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,EAAE,KAAK,IAAI;AAEX,QAAM,cAAc;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,mCAAmC,YAAY;AAAA,IAC/C,cAAc,wBAAwB;AAAA,IACtC;AAAA,IACA;AAAA,EACD,EAAE,KAAK,IAAI;AAEX,QAAM,iBAAiB,MAAM,SAAS,YAAY,OAAO;AACzD,QAAM,gBAAgB,eAAe,QAAQ;AAC7C,QAAM,eAAe;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA,yBAAyB,QAAQ,UAAU;AAAA,IAC3C;AAAA,IACA;AAAA,IACA;AAAA,EACD,EAAE,KAAK,IAAI;AACX,QAAM,iBAAiB,GAAG,aAAa,GAAG,YAAY;AAEtD,QAAM,UAAU,YAAY,gBAAgB,OAAO;AACnD,QAAM,UAAU,SAAS,aAAa,OAAO;AAC7C,QAAM,UAAU,YAAY,gBAAgB,OAAO;AACpD;AAEA,SAAS,eAAe,UAAiC;AACxD,SAAO,aAAa,gBAAgB,aAAa,yBAAyB,aAAa;AACxF;AAEA,SAAS,uBAAuB,UAA0C;AACzE,UAAQ,UAAU;AAAA,IACjB,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,EACT;AACD;AAEA,SAAS,mCAAmC,UAA0C;AACrF,UAAQ,UAAU;AAAA,IACjB,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,EACT;AACD;;;ACpIA,SAAS,QAAQ,YAAAC,iBAAgB;AACjC,SAAS,SAAS,QAAAC,OAAM,eAAe;AAGvC,eAAsB,gBAAgB,MAAgC;AACrE,MAAI;AACH,UAAM,OAAO,IAAI;AACjB,WAAO;AAAA,EACR,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AASA,eAAsB,gBAAgB,UAA2C;AAChF,MAAI,UAAU,QAAQ,YAAY,QAAQ,IAAI,CAAC;AAG/C,aAAS;AACR,UAAM,UAAUA,MAAK,SAAS,cAAc;AAC5C,QAAI;AACH,YAAM,UAAU,MAAMD,UAAS,SAAS,OAAO;AAC/C,YAAM,MAAe,KAAK,MAAM,OAAO;AACvC,UAAI,cAAc,GAAG,GAAG;AACvB,eAAO;AAAA,MACR;AAAA,IACD,QAAQ;AAAA,IAER;AACA,UAAM,SAAS,QAAQ,OAAO;AAC9B,QAAI,WAAW,QAAS;AACxB,cAAU;AAAA,EACX;AAEA,SAAO;AACR;AAQA,eAAsB,eAAe,aAA6C;AACjF,QAAM,aAAa;AAAA,IAClBC,MAAK,aAAa,OAAO,WAAW;AAAA,IACpCA,MAAK,aAAa,WAAW;AAAA,IAC7BA,MAAK,aAAa,OAAO,WAAW;AAAA,IACpCA,MAAK,aAAa,WAAW;AAAA,EAC9B;AAEA,aAAW,aAAa,YAAY;AACnC,QAAI;AACH,YAAM,OAAO,SAAS;AACtB,aAAO;AAAA,IACR,QAAQ;AAAA,IAER;AAAA,EACD;AAEA,SAAO;AACR;AAoCA,eAAsB,gBAAgB,aAAuC;AAC5E,MAAI;AACH,UAAM,OAAOC,MAAK,aAAa,gBAAgB,OAAO,cAAc,CAAC;AACrE,WAAO;AAAA,EACR,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AASA,eAAsB,+BACrB,aACA,aACA,YACyB;AACzB,QAAM,cAAcA,MAAK,aAAa,gBAAgB,aAAa,cAAc;AACjF,MAAI;AACH,UAAM,UAAU,MAAMC,UAAS,aAAa,OAAO;AACnD,UAAM,MAAM,KAAK,MAAM,OAAO;AAC9B,QAAI;AACJ,QAAI,OAAO,IAAI,QAAQ,UAAU;AAChC,gBAAU,IAAI;AAAA,IACf,WAAW,OAAO,IAAI,QAAQ,YAAY,IAAI,QAAQ,MAAM;AAC3D,gBAAU,IAAI,IAAI,UAAU;AAAA,IAC7B;AACA,QAAI,CAAC,QAAS,QAAO;AACrB,UAAM,WAAWD,MAAK,aAAa,gBAAgB,aAAa,OAAO;AACvE,UAAM,OAAO,QAAQ;AACrB,WAAO;AAAA,EACR,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAEA,SAAS,cAAc,KAAuB;AAC7C,MAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM,QAAO;AACpD,QAAM,SAAS;AACf,SAAO,WAAW,OAAO,YAAY,KAAK,WAAW,OAAO,eAAe;AAC5E;AAEA,SAAS,WAAW,MAAwB;AAC3C,MAAI,OAAO,SAAS,YAAY,SAAS,KAAM,QAAO;AACtD,SAAO,OAAO,KAAK,IAAI,EAAE,KAAK,CAAC,QAAQ,QAAQ,UAAU,IAAI,WAAW,UAAU,CAAC;AACpF;;;ACvJA,IAAM,QAAQ;AACd,IAAM,OAAO;AACb,IAAM,MAAM;AACZ,IAAM,QAAQ;AACd,IAAM,SAAS;AACf,IAAM,MAAM;AACZ,IAAM,OAAO;AAqBN,SAAS,aAAa,SAAiC;AAC7D,QAAM,gBACL,SAAS,YAAY,QAAQ,QAAQ,IAAI,aAAa,UAAa,CAAC,QAAQ,OAAO;AAEpF,WAAS,MAAM,MAAc,MAAsB;AAClD,WAAO,gBAAgB,OAAO,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK;AAAA,EACrD;AAEA,SAAO;AAAA,IACN,KAAK,SAAuB;AAC3B,cAAQ,IAAI,MAAM,MAAM,OAAO,CAAC;AAAA,IACjC;AAAA,IACA,QAAQ,SAAuB;AAC9B,cAAQ,IAAI,MAAM,OAAO,YAAO,OAAO,EAAE,CAAC;AAAA,IAC3C;AAAA,IACA,KAAK,SAAuB;AAC3B,cAAQ,KAAK,MAAM,QAAQ,YAAO,OAAO,EAAE,CAAC;AAAA,IAC7C;AAAA,IACA,MAAM,SAAuB;AAC5B,cAAQ,MAAM,MAAM,KAAK,YAAO,OAAO,EAAE,CAAC;AAAA,IAC3C;AAAA,IACA,KAAK,SAAuB;AAC3B,cAAQ,IAAI,MAAM,KAAK,KAAK,OAAO,EAAE,CAAC;AAAA,IACvC;AAAA,IACA,QAAc;AACb,cAAQ,IAAI;AAAA,IACb;AAAA,IACA,SAAe;AACd,cAAQ,IAAI;AACZ,cAAQ;AAAA,QACP,MAAM,OAAO,MAAM,WAAW,IAAI,MAAM,KAAK,6CAAwC;AAAA,MACtF;AACA,cAAQ,IAAI;AAAA,IACb;AAAA,EACD;AACD;","names":["resolve","readFile","join","join","readFile"]}
@@ -5,7 +5,7 @@ import {
5
5
  createPromptClient,
6
6
  findProjectRoot,
7
7
  resolveProjectBinaryEntryPoint
8
- } from "./chunk-KTSRAPSE.js";
8
+ } from "./chunk-HNVCNPER.js";
9
9
 
10
10
  // src/commands/deploy/adapters/adapter.ts
11
11
  var DEPLOY_PLATFORMS = ["fly", "railway", "aws-ecs", "aws-lightsail", "render", "docker", "kora-cloud"];
@@ -2299,4 +2299,4 @@ export {
2299
2299
  deployCommand,
2300
2300
  generateTypes
2301
2301
  };
2302
- //# sourceMappingURL=chunk-E7OCVRYL.js.map
2302
+ //# sourceMappingURL=chunk-MIMLCXSX.js.map
@@ -13,7 +13,7 @@ import {
13
13
  saveResolvedPreferences,
14
14
  shouldSavePreferences,
15
15
  validateProjectName
16
- } from "./chunk-KTSRAPSE.js";
16
+ } from "./chunk-HNVCNPER.js";
17
17
 
18
18
  // src/commands/create/create-command.ts
19
19
  import { execSync as execSync2 } from "child_process";
@@ -237,6 +237,18 @@ function createCompatibilityLayerPlan(templateName) {
237
237
  authLayer
238
238
  ]
239
239
  };
240
+ case "tauri-react":
241
+ return {
242
+ compatibilityTarget: templateName,
243
+ layers: [
244
+ { category: "base", name: "tauri", sourceTemplate: "tauri-react" },
245
+ uiLayer,
246
+ { category: "style", name: "plain", sourceTemplate: null },
247
+ { category: "sync", name: "enabled", sourceTemplate: null },
248
+ { category: "db", name: "tauri-sqlite", sourceTemplate: null },
249
+ authLayer
250
+ ]
251
+ };
240
252
  }
241
253
  }
242
254
  async function composeTemplateLayers(plan, targetDir, context) {
@@ -292,9 +304,13 @@ var createCommand = defineCommand({
292
304
  description: "Project directory name",
293
305
  required: false
294
306
  },
307
+ platform: {
308
+ type: "string",
309
+ description: "Target platform (web, desktop-tauri)"
310
+ },
295
311
  template: {
296
312
  type: "string",
297
- description: "Project template (react-tailwind-sync, react-tailwind, react-sync, react-basic)"
313
+ description: "Project template (react-tailwind-sync, react-tailwind, react-sync, react-basic, tauri-react)"
298
314
  },
299
315
  pm: {
300
316
  type: "string",
@@ -365,6 +381,7 @@ var createCommand = defineCommand({
365
381
  return;
366
382
  }
367
383
  const preferenceFlags = {
384
+ platform: typeof args.platform === "string" ? args.platform : void 0,
368
385
  framework: typeof args.framework === "string" ? args.framework : void 0,
369
386
  auth: typeof args.auth === "string" ? args.auth : void 0,
370
387
  db: typeof args.db === "string" ? args.db : void 0,
@@ -472,6 +489,7 @@ var createCommand = defineCommand({
472
489
  logger.success("Project scaffolded");
473
490
  if (shouldSavePreferences(preferenceFlags)) {
474
491
  saveResolvedPreferences(preferenceStore, {
492
+ platform: selection.platform,
475
493
  framework: selection.framework,
476
494
  auth: selection.auth,
477
495
  db: selection.db,
@@ -523,7 +541,7 @@ function isValidPackageManager(value) {
523
541
  return PACKAGE_MANAGERS.includes(value);
524
542
  }
525
543
  function isSyncTemplate(template) {
526
- return template === "react-sync" || template === "react-tailwind-sync";
544
+ return template === "react-sync" || template === "react-tailwind-sync" || template === "tauri-react";
527
545
  }
528
546
  function formatDbProviderForLog(dbProvider) {
529
547
  switch (dbProvider) {
@@ -606,4 +624,4 @@ function resolveKoraVersion() {
606
624
  export {
607
625
  createCommand
608
626
  };
609
- //# sourceMappingURL=chunk-ZGYRDYXS.js.map
627
+ //# sourceMappingURL=chunk-ULTO5NFA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/create/create-command.ts","../src/utils/package-manager.ts","../src/commands/create/environment-detection.ts","../src/templates/composer.ts","../src/commands/create/template-engine.ts"],"sourcesContent":["import { execSync } from 'node:child_process'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { defineCommand } from 'citty'\nimport { ProjectExistsError } from '../../errors'\nimport { PreferenceStore } from '../../prompts/preferences'\nimport { PromptCancelledError, createPromptClient } from '../../prompts/prompt-client'\nimport { PACKAGE_MANAGERS, TEMPLATES } from '../../types'\nimport type { PackageManager, TemplateName } from '../../types'\nimport { directoryExists } from '../../utils/fs-helpers'\nimport { createLogger } from '../../utils/logger'\nimport {\n\tdetectPackageManager,\n\tgetInstallCommand,\n\tgetRunDevCommand,\n} from '../../utils/package-manager'\nimport {\n\tapplyEditorWorkspacePreset,\n\tdetectEditorFromEnvironment,\n\tdetectGitContext,\n\tdetectMonorepoContext,\n\tresolveMonorepoTargetDirectory,\n} from './environment-detection'\nimport {\n\ttype CreateFlags,\n\tresolveCreatePreferencesFlow,\n\tsaveResolvedPreferences,\n\tshouldSavePreferences,\n} from './preferences-flow'\nimport { validateProjectName } from './project-name'\nimport { applySyncProviderPreset } from './sync-provider-preset'\nimport { scaffoldTemplate } from './template-engine'\n\n/**\n * The `create` command — scaffolds a new Kora project.\n * Used as `kora create <name>` or `create-kora-app <name>`.\n */\nexport const createCommand = defineCommand({\n\tmeta: {\n\t\tname: 'create',\n\t\tdescription: 'Create a new Kora application',\n\t},\n\targs: {\n\t\tname: {\n\t\t\ttype: 'positional',\n\t\t\tdescription: 'Project directory name',\n\t\t\trequired: false,\n\t\t},\n\t\tplatform: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Target platform (web, desktop-tauri)',\n\t\t},\n\t\ttemplate: {\n\t\t\ttype: 'string',\n\t\t\tdescription:\n\t\t\t\t'Project template (react-tailwind-sync, react-tailwind, react-sync, react-basic, tauri-react)',\n\t\t},\n\t\tpm: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Package manager (pnpm, npm, yarn, bun)',\n\t\t},\n\t\tframework: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'UI framework (react, vue, svelte, solid)',\n\t\t},\n\t\tdb: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Database backend for sync templates (sqlite, postgres)',\n\t\t},\n\t\t'db-provider': {\n\t\t\ttype: 'string',\n\t\t\tdescription:\n\t\t\t\t'Database provider for postgres (local, supabase, neon, railway, vercel-postgres, custom)',\n\t\t},\n\t\tauth: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Authentication mode (none, email-password, oauth)',\n\t\t},\n\t\t'skip-install': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Skip installing dependencies',\n\t\t\tdefault: false,\n\t\t},\n\t\tyes: {\n\t\t\ttype: 'boolean',\n\t\t\talias: 'y',\n\t\t\tdescription: 'Accept all defaults (react-tailwind-sync + detected package manager)',\n\t\t\tdefault: false,\n\t\t},\n\t\ttailwind: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Use Tailwind CSS (use --no-tailwind to skip)',\n\t\t},\n\t\tsync: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Include sync server (use --no-sync to skip)',\n\t\t},\n\t},\n\tasync run({ args }) {\n\t\tconst logger = createLogger()\n\t\tconst prompts = createPromptClient()\n\t\tconst preferenceStore = new PreferenceStore()\n\t\tlogger.banner()\n\t\ttry {\n\t\t\tconst useDefaults = args.yes === true\n\t\t\tif (!useDefaults) {\n\t\t\t\tprompts.intro('Kora.js — Offline-first application framework')\n\t\t\t}\n\n\t\t\t// Resolve project name\n\t\t\tconst projectName =\n\t\t\t\targs.name ||\n\t\t\t\t(useDefaults ? 'my-kora-app' : await prompts.text('Project name', 'my-kora-app'))\n\t\t\tif (!projectName) {\n\t\t\t\tlogger.error('Project name is required')\n\t\t\t\tprocess.exitCode = 1\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst nameValidation = validateProjectName(projectName)\n\t\t\tif (!nameValidation.valid) {\n\t\t\t\tlogger.error('Invalid project name.')\n\t\t\t\tfor (const issue of nameValidation.issues) {\n\t\t\t\t\tlogger.step(`- ${issue}`)\n\t\t\t\t}\n\t\t\t\tif (!useDefaults) {\n\t\t\t\t\tprompts.outro('Project creation aborted.')\n\t\t\t\t}\n\t\t\t\tprocess.exitCode = 1\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst preferenceFlags: CreateFlags = {\n\t\t\t\tplatform: typeof args.platform === 'string' ? args.platform : undefined,\n\t\t\t\tframework: typeof args.framework === 'string' ? args.framework : undefined,\n\t\t\t\tauth: typeof args.auth === 'string' ? args.auth : undefined,\n\t\t\t\tdb: typeof args.db === 'string' ? args.db : undefined,\n\t\t\t\tdbProvider: typeof args['db-provider'] === 'string' ? args['db-provider'] : undefined,\n\t\t\t\ttailwind: args.tailwind,\n\t\t\t\tsync: args.sync,\n\t\t\t\tuseDefaults,\n\t\t\t}\n\n\t\t\tconst selection = await resolveCreatePreferencesFlow({\n\t\t\t\tflags: preferenceFlags,\n\t\t\t\tprompts,\n\t\t\t\tstore: preferenceStore,\n\t\t\t})\n\t\t\tif (selection.framework !== 'react') {\n\t\t\t\tlogger.error(`Framework \"${selection.framework}\" is not available yet. Use \"react\".`)\n\t\t\t\tif (!useDefaults) {\n\t\t\t\t\tprompts.outro('Project creation aborted.')\n\t\t\t\t}\n\t\t\t\tprocess.exitCode = 1\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (selection.auth !== 'none') {\n\t\t\t\tlogger.error(`Auth mode \"${selection.auth}\" is not available yet. Use \"none\".`)\n\t\t\t\tif (!useDefaults) {\n\t\t\t\t\tprompts.outro('Project creation aborted.')\n\t\t\t\t}\n\t\t\t\tprocess.exitCode = 1\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Resolve template (explicit --template still overrides all selections).\n\t\t\tconst template: TemplateName =\n\t\t\t\targs.template && isValidTemplate(args.template) ? args.template : selection.template\n\n\t\t\t// Resolve package manager\n\t\t\tlet pm: PackageManager\n\t\t\tif (args.pm && isValidPackageManager(args.pm)) {\n\t\t\t\tpm = args.pm\n\t\t\t} else if (useDefaults) {\n\t\t\t\tpm = detectPackageManager()\n\t\t\t} else if (selection.usedStoredPreferences) {\n\t\t\t\tpm = preferenceStore.getCreatePreferences()?.packageManager ?? detectPackageManager()\n\t\t\t} else {\n\t\t\t\tconst detected = detectPackageManager()\n\t\t\t\tpm = await prompts.select(\n\t\t\t\t\t'Package manager:',\n\t\t\t\t\tPACKAGE_MANAGERS.map((p) => ({\n\t\t\t\t\t\tlabel: p === detected ? `${p} (detected)` : p,\n\t\t\t\t\t\tvalue: p,\n\t\t\t\t\t})),\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tconst editorDetection = detectEditorFromEnvironment()\n\t\t\tconst gitContext = await detectGitContext(process.cwd())\n\t\t\tconst monorepoContext = await detectMonorepoContext(process.cwd())\n\n\t\t\tlet targetDir = resolve(process.cwd(), projectName)\n\t\t\tif (!useDefaults && monorepoContext.isMonorepo && monorepoContext.root !== null) {\n\t\t\t\tconst useWorkspaceTarget = await prompts.confirm(\n\t\t\t\t\t`Detected ${formatMonorepoKind(monorepoContext.kind)} at ${monorepoContext.root}. Create app under packages/${projectName}?`,\n\t\t\t\t\ttrue,\n\t\t\t\t)\n\t\t\t\tif (useWorkspaceTarget) {\n\t\t\t\t\ttargetDir = resolveMonorepoTargetDirectory(monorepoContext.root, projectName)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Validate target directory\n\t\t\tif (await directoryExists(targetDir)) {\n\t\t\t\tthrow new ProjectExistsError(projectName)\n\t\t\t}\n\n\t\t\t// Resolve kora version from this package's own package.json\n\t\t\tconst koraVersion = resolveKoraVersion()\n\n\t\t\t// Scaffold\n\t\t\tlogger.step(`Creating ${projectName} with ${template} template...`)\n\t\t\tawait scaffoldTemplate(template, targetDir, {\n\t\t\t\tprojectName,\n\t\t\t\tpackageManager: pm,\n\t\t\t\tkoraVersion,\n\t\t\t\tdbProvider: selection.dbProvider,\n\t\t\t})\n\t\t\tawait applySyncProviderPreset({\n\t\t\t\ttargetDir,\n\t\t\t\ttemplate,\n\t\t\t\tdb: selection.db,\n\t\t\t\tdbProvider: selection.dbProvider,\n\t\t\t})\n\t\t\tif (!useDefaults && editorDetection.editor !== 'unknown') {\n\t\t\t\tconst shouldApplyEditorPreset = await prompts.confirm(\n\t\t\t\t\t`Detected ${formatEditor(editorDetection.editor)}. Add workspace recommendations for ${formatEditor(editorDetection.editor)}?`,\n\t\t\t\t\ttrue,\n\t\t\t\t)\n\t\t\t\tif (shouldApplyEditorPreset) {\n\t\t\t\t\tconst appliedPreset = await applyEditorWorkspacePreset({\n\t\t\t\t\t\ttargetDir,\n\t\t\t\t\t\teditor: editorDetection.editor,\n\t\t\t\t\t})\n\t\t\t\t\tif (appliedPreset.applied) {\n\t\t\t\t\t\tlogger.step(\n\t\t\t\t\t\t\t`Added editor recommendations at ${relativeToTarget(targetDir, appliedPreset.filePath)}`,\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (selection.db === 'postgres' && isSyncTemplate(template)) {\n\t\t\t\tlogger.info(\n\t\t\t\t\t`Applied PostgreSQL sync preset (${formatDbProviderForLog(selection.dbProvider)}). Update DATABASE_URL in .env.example before running the sync server.`,\n\t\t\t\t)\n\t\t\t}\n\t\t\tif (gitContext.hasRepository) {\n\t\t\t\tlogger.step(\n\t\t\t\t\t`Detected existing git repository at ${gitContext.repositoryRoot}. Skipping git initialization.`,\n\t\t\t\t)\n\t\t\t}\n\t\t\tlogger.success('Project scaffolded')\n\n\t\t\tif (shouldSavePreferences(preferenceFlags)) {\n\t\t\t\tsaveResolvedPreferences(preferenceStore, {\n\t\t\t\t\tplatform: selection.platform,\n\t\t\t\t\tframework: selection.framework,\n\t\t\t\t\tauth: selection.auth,\n\t\t\t\t\tdb: selection.db,\n\t\t\t\t\tdbProvider: selection.dbProvider,\n\t\t\t\t\ttailwind: selection.tailwind,\n\t\t\t\t\tsync: selection.sync,\n\t\t\t\t\tpackageManager: pm,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// Install dependencies\n\t\t\tif (!args['skip-install']) {\n\t\t\t\tlogger.step('Installing dependencies...')\n\t\t\t\ttry {\n\t\t\t\t\texecSync(getInstallCommand(pm), { cwd: targetDir, stdio: 'inherit' })\n\t\t\t\t\tlogger.success('Dependencies installed')\n\t\t\t\t} catch {\n\t\t\t\t\tlogger.warn('Failed to install dependencies. Run install manually.')\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Print next steps\n\t\t\tlogger.blank()\n\t\t\tlogger.info('Done! Next steps:')\n\t\t\tlogger.blank()\n\t\t\tlogger.step(` cd ${targetDir}`)\n\t\t\tlogger.step(` ${getRunDevCommand(pm)}`)\n\t\t\tlogger.blank()\n\t\t\tif (!useDefaults) {\n\t\t\t\tprompts.outro('Project ready. Happy building with Kora!')\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof PromptCancelledError) {\n\t\t\t\tprocess.exitCode = 1\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (error instanceof Error && error.message.startsWith('Invalid --')) {\n\t\t\t\tlogger.error(error.message)\n\t\t\t\tif (!args.yes) {\n\t\t\t\t\tprompts.outro('Project creation aborted.')\n\t\t\t\t}\n\t\t\t\tprocess.exitCode = 1\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t},\n})\n\nfunction isValidTemplate(value: string): value is TemplateName {\n\treturn (TEMPLATES as readonly string[]).includes(value)\n}\n\nfunction isValidPackageManager(value: string): value is PackageManager {\n\treturn (PACKAGE_MANAGERS as readonly string[]).includes(value)\n}\n\nfunction isSyncTemplate(template: TemplateName): boolean {\n\treturn template === 'react-sync' || template === 'react-tailwind-sync' || template === 'tauri-react'\n}\n\nfunction formatDbProviderForLog(dbProvider: string): string {\n\tswitch (dbProvider) {\n\t\tcase 'supabase':\n\t\t\treturn 'Supabase'\n\t\tcase 'neon':\n\t\t\treturn 'Neon'\n\t\tcase 'railway':\n\t\t\treturn 'Railway'\n\t\tcase 'vercel-postgres':\n\t\t\treturn 'Vercel Postgres'\n\t\tcase 'custom':\n\t\t\treturn 'Custom'\n\t\tcase 'local':\n\t\t\treturn 'Local Postgres'\n\t\tcase 'none':\n\t\t\treturn 'PostgreSQL'\n\t\tdefault:\n\t\t\treturn dbProvider\n\t}\n}\n\nfunction formatEditor(editor: string): string {\n\tswitch (editor) {\n\t\tcase 'vscode':\n\t\t\treturn 'VS Code'\n\t\tcase 'cursor':\n\t\t\treturn 'Cursor'\n\t\tcase 'windsurf':\n\t\t\treturn 'Windsurf'\n\t\tcase 'zed':\n\t\t\treturn 'Zed'\n\t\tdefault:\n\t\t\treturn editor\n\t}\n}\n\nfunction formatMonorepoKind(kind: string): string {\n\tswitch (kind) {\n\t\tcase 'pnpm-workspace':\n\t\t\treturn 'pnpm workspace'\n\t\tcase 'npm-workspaces':\n\t\t\treturn 'npm workspace'\n\t\tcase 'turborepo':\n\t\t\treturn 'Turborepo'\n\t\tdefault:\n\t\t\treturn 'monorepo'\n\t}\n}\n\nfunction relativeToTarget(targetDir: string, filePath: string | null): string {\n\tif (filePath === null) return '.'\n\tconst normalizedTarget = targetDir.endsWith('/') ? targetDir : `${targetDir}/`\n\tif (filePath.startsWith(normalizedTarget)) {\n\t\treturn filePath.slice(normalizedTarget.length)\n\t}\n\tif (filePath === targetDir) {\n\t\treturn '.'\n\t}\n\treturn filePath\n}\n\n/**\n * Reads the version from @korajs/cli's own package.json and derives a\n * compatible version range for all @korajs packages.\n *\n * The CLI may be a patch ahead of other packages (e.g. CLI-only fixes),\n * so we use the major.minor range (^major.minor.0) which matches all\n * packages in the same release series.\n */\nfunction resolveKoraVersion(): string {\n\ttry {\n\t\tlet dir = dirname(fileURLToPath(import.meta.url))\n\t\tfor (let i = 0; i < 5; i++) {\n\t\t\tconst pkgPath = resolve(dir, 'package.json')\n\t\t\tif (existsSync(pkgPath)) {\n\t\t\t\tconst pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as { name?: string; version: string }\n\t\t\t\tif (pkg.name === '@korajs/cli') {\n\t\t\t\t\tif (pkg.version === '0.0.0') return 'latest'\n\t\t\t\t\t// Use ^major.minor.0 so all packages in the series match\n\t\t\t\t\tconst parts = pkg.version.split('.')\n\t\t\t\t\treturn `^${parts[0]}.${parts[1]}.0`\n\t\t\t\t}\n\t\t\t}\n\t\t\tdir = dirname(dir)\n\t\t}\n\t\treturn 'latest'\n\t} catch {\n\t\treturn 'latest'\n\t}\n}\n","import { execSync } from 'node:child_process'\nimport type { PackageManager } from '../types'\n\n/**\n * Detects the package manager used to invoke the current process\n * by reading the npm_config_user_agent environment variable.\n * Falls back to 'npm' if detection fails.\n */\nexport function detectPackageManager(): PackageManager {\n\tconst userAgent = process.env.npm_config_user_agent\n\tif (!userAgent) return 'npm'\n\n\tif (userAgent.startsWith('pnpm/')) return 'pnpm'\n\tif (userAgent.startsWith('yarn/')) return 'yarn'\n\tif (userAgent.startsWith('bun/')) return 'bun'\n\treturn 'npm'\n}\n\n/** Returns the install command for the given package manager */\nexport function getInstallCommand(pm: PackageManager): string {\n\treturn pm === 'yarn' ? 'yarn' : `${pm} install`\n}\n\n/** Returns the dev server run command for the given package manager */\nexport function getRunDevCommand(pm: PackageManager): string {\n\tif (pm === 'npm') return 'npm run dev'\n\treturn `${pm} dev`\n}\n\n/** Checks if a package manager is available on PATH */\nexport function isPackageManagerAvailable(pm: PackageManager): boolean {\n\ttry {\n\t\texecSync(`${pm} --version`, { stdio: 'ignore' })\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n","import { access, mkdir, readFile, stat, writeFile } from 'node:fs/promises'\nimport { dirname, join, resolve } from 'node:path'\n\nexport type SupportedEditor = 'vscode' | 'cursor' | 'windsurf' | 'zed' | 'unknown'\n\nexport interface EditorDetectionResult {\n\teditor: SupportedEditor\n\tsource: 'env' | 'none'\n}\n\nexport interface GitContextResult {\n\thasRepository: boolean\n\trepositoryRoot: string | null\n}\n\nexport interface MonorepoContextResult {\n\tisMonorepo: boolean\n\troot: string | null\n\tkind: 'pnpm-workspace' | 'npm-workspaces' | 'turborepo' | 'none'\n}\n\nexport interface EditorWorkspacePresetResult {\n\tapplied: boolean\n\tfilePath: string | null\n}\n\n/**\n * Detects which editor is most likely being used by inspecting environment\n * variables commonly set by integrated terminals.\n */\nexport function detectEditorFromEnvironment(\n\tenv: Record<string, string | undefined> = process.env,\n): EditorDetectionResult {\n\tconst termProgram = String(env.TERM_PROGRAM ?? '').toLowerCase()\n\tconst editorValue = `${String(env.EDITOR ?? '')} ${String(env.VISUAL ?? '')}`.toLowerCase()\n\n\tif (\n\t\ttermProgram.includes('cursor') ||\n\t\tenv.CURSOR_TRACE_ID !== undefined ||\n\t\tenv.CURSOR_SESSION_ID !== undefined ||\n\t\teditorValue.includes('cursor')\n\t) {\n\t\treturn { editor: 'cursor', source: 'env' }\n\t}\n\tif (\n\t\ttermProgram.includes('windsurf') ||\n\t\tenv.WINDSURF_SESSION_ID !== undefined ||\n\t\teditorValue.includes('windsurf')\n\t) {\n\t\treturn { editor: 'windsurf', source: 'env' }\n\t}\n\tif (\n\t\ttermProgram.includes('vscode') ||\n\t\tenv.VSCODE_GIT_IPC_HANDLE !== undefined ||\n\t\tenv.VSCODE_IPC_HOOK !== undefined ||\n\t\tenv.VSCODE_PID !== undefined ||\n\t\teditorValue.includes('code')\n\t) {\n\t\treturn { editor: 'vscode', source: 'env' }\n\t}\n\tif (termProgram.includes('zed') || env.ZED_TERM !== undefined || editorValue.includes('zed')) {\n\t\treturn { editor: 'zed', source: 'env' }\n\t}\n\treturn { editor: 'unknown', source: 'none' }\n}\n\n/**\n * Finds the nearest ancestor directory that contains a `.git` entry.\n */\nexport async function detectGitContext(startDir: string): Promise<GitContextResult> {\n\tconst root = await findNearestAncestorWithEntry(startDir, '.git')\n\treturn {\n\t\thasRepository: root !== null,\n\t\trepositoryRoot: root,\n\t}\n}\n\n/**\n * Detects whether the given path is inside a monorepo workspace.\n * Detection currently supports pnpm workspaces, npm workspaces, and Turborepo.\n */\nexport async function detectMonorepoContext(startDir: string): Promise<MonorepoContextResult> {\n\tlet current = resolve(startDir)\n\tfor (;;) {\n\t\tif (await fileExists(join(current, 'pnpm-workspace.yaml'))) {\n\t\t\treturn { isMonorepo: true, root: current, kind: 'pnpm-workspace' }\n\t\t}\n\n\t\tif (await fileExists(join(current, 'turbo.json'))) {\n\t\t\treturn { isMonorepo: true, root: current, kind: 'turborepo' }\n\t\t}\n\n\t\tconst packageJsonPath = join(current, 'package.json')\n\t\tif (await fileExists(packageJsonPath)) {\n\t\t\ttry {\n\t\t\t\tconst packageJsonRaw = await readFile(packageJsonPath, 'utf-8')\n\t\t\t\tconst parsed = JSON.parse(packageJsonRaw) as { workspaces?: unknown }\n\t\t\t\tif (Array.isArray(parsed.workspaces) || isNpmWorkspaceObject(parsed.workspaces)) {\n\t\t\t\t\treturn { isMonorepo: true, root: current, kind: 'npm-workspaces' }\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Ignore malformed package.json and keep walking upward.\n\t\t\t}\n\t\t}\n\n\t\tconst parent = dirname(current)\n\t\tif (parent === current) {\n\t\t\treturn { isMonorepo: false, root: null, kind: 'none' }\n\t\t}\n\t\tcurrent = parent\n\t}\n}\n\n/**\n * Applies editor-specific workspace configuration. For VS Code-compatible\n * editors this creates or updates `.vscode/extensions.json` recommendations.\n */\nexport async function applyEditorWorkspacePreset(params: {\n\ttargetDir: string\n\teditor: SupportedEditor\n}): Promise<EditorWorkspacePresetResult> {\n\tconst { targetDir, editor } = params\n\tif (editor !== 'vscode' && editor !== 'cursor' && editor !== 'windsurf') {\n\t\treturn { applied: false, filePath: null }\n\t}\n\n\tconst vscodeDir = join(targetDir, '.vscode')\n\tconst extensionsPath = join(vscodeDir, 'extensions.json')\n\tawait mkdir(vscodeDir, { recursive: true })\n\n\tconst recommendations = ['korajs.kora-devtools']\n\tconst existing = await readJsonObject(extensionsPath)\n\tconst existingRecommendations = Array.isArray(existing?.recommendations)\n\t\t? existing.recommendations.filter((item): item is string => typeof item === 'string')\n\t\t: []\n\tconst mergedRecommendations = dedupeStrings([...existingRecommendations, ...recommendations])\n\n\tconst next = {\n\t\trecommendations: mergedRecommendations,\n\t}\n\tawait writeFile(extensionsPath, `${JSON.stringify(next, null, 2)}\\n`, 'utf-8')\n\treturn { applied: true, filePath: extensionsPath }\n}\n\n/**\n * Returns a workspace-aware target directory under the detected monorepo root.\n * This keeps generated apps in conventional package folders.\n */\nexport function resolveMonorepoTargetDirectory(monorepoRoot: string, projectName: string): string {\n\treturn join(monorepoRoot, 'packages', projectName)\n}\n\nfunction dedupeStrings(values: readonly string[]): string[] {\n\treturn Array.from(new Set(values))\n}\n\nasync function readJsonObject(path: string): Promise<Record<string, unknown> | null> {\n\ttry {\n\t\tconst content = await readFile(path, 'utf-8')\n\t\tconst parsed: unknown = JSON.parse(content)\n\t\tif (typeof parsed === 'object' && parsed !== null) {\n\t\t\treturn parsed as Record<string, unknown>\n\t\t}\n\t\treturn null\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction isNpmWorkspaceObject(value: unknown): value is { packages: unknown } {\n\tif (typeof value !== 'object' || value === null) return false\n\tconst record = value as Record<string, unknown>\n\treturn Array.isArray(record.packages)\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n\ttry {\n\t\tawait access(path)\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n\nasync function findNearestAncestorWithEntry(\n\tstartDir: string,\n\tentryName: string,\n): Promise<string | null> {\n\tlet current = resolve(startDir)\n\tfor (;;) {\n\t\tconst candidate = join(current, entryName)\n\t\ttry {\n\t\t\tawait stat(candidate)\n\t\t\treturn current\n\t\t} catch {\n\t\t\t// keep walking upward\n\t\t}\n\t\tconst parent = dirname(current)\n\t\tif (parent === current) {\n\t\t\treturn null\n\t\t}\n\t\tcurrent = parent\n\t}\n}\n","import { existsSync } from 'node:fs'\nimport { copyFile, mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises'\nimport { dirname, join, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { TemplateContext, TemplateName } from '../types'\n\nexport type TemplateLayerCategory = 'base' | 'ui' | 'style' | 'sync' | 'db' | 'auth'\n\nexport interface TemplateLayer {\n\tcategory: TemplateLayerCategory\n\tname: string\n\tsourceTemplate: TemplateName | null\n}\n\nexport interface TemplateLayerPlan {\n\tlayers: readonly TemplateLayer[]\n\tcompatibilityTarget: TemplateName\n}\n\n/**\n * Replaces {{variable}} placeholders in a template string with context values.\n *\n * @param template - The template string containing {{variable}} placeholders\n * @param context - Key-value pairs to substitute\n * @returns The template with all placeholders replaced\n */\nexport function substituteVariables(template: string, context: Record<string, string>): string {\n\treturn template.replace(/\\{\\{(\\w+)\\}\\}/g, (_match, key: string) => {\n\t\tconst value = context[key]\n\t\treturn value !== undefined ? value : `{{${key}}}`\n\t})\n}\n\n/**\n * Resolves the absolute path to a bundled template directory.\n *\n * After tsup bundling, import.meta.url points to dist/<file>.js (1 level from root).\n * In source, it's src/templates/composer.ts (2 levels from root).\n * We walk up from the current file to find the package root containing templates/.\n *\n * @param templateName - Name of the template (for example, 'react-basic')\n * @returns Absolute path to the template directory\n */\nexport function getTemplatePath(templateName: TemplateName): string {\n\tlet dir = dirname(fileURLToPath(import.meta.url))\n\tfor (let i = 0; i < 7; i++) {\n\t\tconst candidate = resolve(dir, 'templates', templateName)\n\t\tif (existsSync(candidate)) {\n\t\t\treturn candidate\n\t\t}\n\t\tdir = dirname(dir)\n\t}\n\t// Fallback: assume bundled output and step to package root.\n\tconst currentDir = dirname(fileURLToPath(import.meta.url))\n\treturn resolve(currentDir, '..', '..', '..', 'templates', templateName)\n}\n\n/**\n * Returns a v1 compatibility layer plan that composes to one of the existing\n * four concrete templates. This establishes the layer architecture while\n * preserving byte-for-byte output compatibility for current templates.\n */\nexport function createCompatibilityLayerPlan(templateName: TemplateName): TemplateLayerPlan {\n\tconst baseLayer: TemplateLayer = { category: 'base', name: 'base', sourceTemplate: 'react-basic' }\n\tconst uiLayer: TemplateLayer = { category: 'ui', name: 'react', sourceTemplate: null }\n\tconst authLayer: TemplateLayer = { category: 'auth', name: 'none', sourceTemplate: null }\n\n\tswitch (templateName) {\n\t\tcase 'react-basic':\n\t\t\treturn {\n\t\t\t\tcompatibilityTarget: templateName,\n\t\t\t\tlayers: [\n\t\t\t\t\tbaseLayer,\n\t\t\t\t\tuiLayer,\n\t\t\t\t\t{ category: 'style', name: 'plain', sourceTemplate: null },\n\t\t\t\t\t{ category: 'sync', name: 'disabled', sourceTemplate: null },\n\t\t\t\t\t{ category: 'db', name: 'none', sourceTemplate: null },\n\t\t\t\t\tauthLayer,\n\t\t\t\t],\n\t\t\t}\n\t\tcase 'react-tailwind':\n\t\t\treturn {\n\t\t\t\tcompatibilityTarget: templateName,\n\t\t\t\tlayers: [\n\t\t\t\t\tbaseLayer,\n\t\t\t\t\tuiLayer,\n\t\t\t\t\t{ category: 'style', name: 'tailwind', sourceTemplate: 'react-tailwind' },\n\t\t\t\t\t{ category: 'sync', name: 'disabled', sourceTemplate: null },\n\t\t\t\t\t{ category: 'db', name: 'none', sourceTemplate: null },\n\t\t\t\t\tauthLayer,\n\t\t\t\t],\n\t\t\t}\n\t\tcase 'react-sync':\n\t\t\treturn {\n\t\t\t\tcompatibilityTarget: templateName,\n\t\t\t\tlayers: [\n\t\t\t\t\tbaseLayer,\n\t\t\t\t\tuiLayer,\n\t\t\t\t\t{ category: 'style', name: 'plain', sourceTemplate: null },\n\t\t\t\t\t{ category: 'sync', name: 'enabled', sourceTemplate: 'react-sync' },\n\t\t\t\t\t{ category: 'db', name: 'sqlite', sourceTemplate: null },\n\t\t\t\t\tauthLayer,\n\t\t\t\t],\n\t\t\t}\n\t\tcase 'react-tailwind-sync':\n\t\t\treturn {\n\t\t\t\tcompatibilityTarget: templateName,\n\t\t\t\tlayers: [\n\t\t\t\t\tbaseLayer,\n\t\t\t\t\tuiLayer,\n\t\t\t\t\t{ category: 'style', name: 'tailwind', sourceTemplate: 'react-tailwind' },\n\t\t\t\t\t{ category: 'sync', name: 'enabled', sourceTemplate: 'react-tailwind-sync' },\n\t\t\t\t\t{ category: 'db', name: 'sqlite', sourceTemplate: null },\n\t\t\t\t\tauthLayer,\n\t\t\t\t],\n\t\t\t}\n\t\tcase 'tauri-react':\n\t\t\treturn {\n\t\t\t\tcompatibilityTarget: templateName,\n\t\t\t\tlayers: [\n\t\t\t\t\t{ category: 'base', name: 'tauri', sourceTemplate: 'tauri-react' },\n\t\t\t\t\tuiLayer,\n\t\t\t\t\t{ category: 'style', name: 'plain', sourceTemplate: null },\n\t\t\t\t\t{ category: 'sync', name: 'enabled', sourceTemplate: null },\n\t\t\t\t\t{ category: 'db', name: 'tauri-sqlite', sourceTemplate: null },\n\t\t\t\t\tauthLayer,\n\t\t\t\t],\n\t\t\t}\n\t}\n}\n\n/**\n * Composes a project by applying template layers in order. Later layers\n * overwrite earlier files, which allows progressive specialization.\n *\n * @param plan - Layer plan describing the composition\n * @param targetDir - Destination directory (must not exist yet)\n * @param context - Variables for template substitution\n */\nexport async function composeTemplateLayers(\n\tplan: TemplateLayerPlan,\n\ttargetDir: string,\n\tcontext: TemplateContext,\n): Promise<void> {\n\tconst vars: Record<string, string> = {\n\t\tprojectName: context.projectName,\n\t\tpackageManager: context.packageManager,\n\t\tkoraVersion: context.koraVersion,\n\t\tdbProvider: context.dbProvider ?? 'none',\n\t}\n\n\tfor (const layer of plan.layers) {\n\t\tif (layer.sourceTemplate === null) {\n\t\t\tcontinue\n\t\t}\n\t\tconst sourceDir = getTemplatePath(layer.sourceTemplate)\n\t\tawait copyDirectory(sourceDir, targetDir, vars)\n\t}\n}\n\nasync function copyDirectory(\n\tsrc: string,\n\tdest: string,\n\tvars: Record<string, string>,\n): Promise<void> {\n\tawait mkdir(dest, { recursive: true })\n\tconst entries = await readdir(src)\n\n\tfor (const entry of entries) {\n\t\tconst srcPath = join(src, entry)\n\t\tconst srcStat = await stat(srcPath)\n\n\t\tif (srcStat.isDirectory()) {\n\t\t\tawait copyDirectory(srcPath, join(dest, entry), vars)\n\t\t\tcontinue\n\t\t}\n\t\tif (entry.endsWith('.hbs')) {\n\t\t\tconst content = await readFile(srcPath, 'utf-8')\n\t\t\tconst outputName = entry.slice(0, -4)\n\t\t\tawait writeFile(join(dest, outputName), substituteVariables(content, vars), 'utf-8')\n\t\t\tcontinue\n\t\t}\n\t\tawait copyFile(srcPath, join(dest, entry))\n\t}\n}\n","import { composeTemplateLayers, createCompatibilityLayerPlan } from '../../templates/composer'\nimport type { TemplateContext, TemplateName } from '../../types'\n\n/**\n * Replaces {{variable}} placeholders in a template string with context values.\n *\n * @param template - The template string containing {{variable}} placeholders\n * @param context - Key-value pairs to substitute\n * @returns The template with all placeholders replaced\n */\nexport { substituteVariables, getTemplatePath } from '../../templates/composer'\n\n/**\n * Scaffolds a project from a bundled template.\n * Copies all files from the template directory to the target, applying\n * variable substitution to .hbs files and stripping the .hbs extension.\n *\n * @param templateName - Which template to use\n * @param targetDir - Destination directory (must not exist yet)\n * @param context - Variables for template substitution\n */\nexport async function scaffoldTemplate(\n\ttemplateName: TemplateName,\n\ttargetDir: string,\n\tcontext: TemplateContext,\n): Promise<void> {\n\tconst plan = createCompatibilityLayerPlan(templateName)\n\tawait composeTemplateLayers(plan, targetDir, context)\n}\n"],"mappings":"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","names":["execSync","existsSync","dirname","resolve","fileURLToPath","mkdir","readFile","stat","writeFile","dirname","join","resolve","resolve","execSync","dirname","fileURLToPath","existsSync"]}