@korajs/cli 0.6.0 → 1.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/dist/bin.cjs +2582 -202
  3. package/dist/bin.cjs.map +1 -1
  4. package/dist/bin.js +152 -96
  5. package/dist/bin.js.map +1 -1
  6. package/dist/chunk-5NI2FEQL.js +92 -0
  7. package/dist/chunk-5NI2FEQL.js.map +1 -0
  8. package/dist/chunk-6C4BHSRA.js +82 -0
  9. package/dist/chunk-6C4BHSRA.js.map +1 -0
  10. package/dist/{chunk-VLTPEATY.js → chunk-B5YS4STN.js} +9 -96
  11. package/dist/chunk-B5YS4STN.js.map +1 -0
  12. package/dist/{chunk-EEZNRI5W.js → chunk-BWTKRKNJ.js} +13 -5
  13. package/dist/{chunk-EEZNRI5W.js.map → chunk-BWTKRKNJ.js.map} +1 -1
  14. package/dist/{chunk-Q2FBCOQD.js → chunk-EOWLAAIV.js} +5 -3
  15. package/dist/{chunk-Q2FBCOQD.js.map → chunk-EOWLAAIV.js.map} +1 -1
  16. package/dist/create.cjs +8 -2
  17. package/dist/create.cjs.map +1 -1
  18. package/dist/create.js +3 -2
  19. package/dist/create.js.map +1 -1
  20. package/dist/index.js +3 -2
  21. package/dist/lab-manager-KUDII6BT.js +280 -0
  22. package/dist/lab-manager-KUDII6BT.js.map +1 -0
  23. package/dist/schema-loader-GGHECMTM.js +9 -0
  24. package/dist/schema-loader-GGHECMTM.js.map +1 -0
  25. package/dist/spectator-manager-E2LH2P54.js +142 -0
  26. package/dist/spectator-manager-E2LH2P54.js.map +1 -0
  27. package/dist/studio-server-NIFKZI4F.js +1738 -0
  28. package/dist/studio-server-NIFKZI4F.js.map +1 -0
  29. package/package.json +8 -6
  30. package/templates/react-basic/AGENTS.md +87 -0
  31. package/templates/react-sync/AGENTS.md +87 -0
  32. package/templates/react-sync/src/App.tsx +8 -0
  33. package/templates/react-sync/src/index.css +11 -0
  34. package/templates/react-tailwind/AGENTS.md +87 -0
  35. package/templates/react-tailwind-sync/AGENTS.md +87 -0
  36. package/templates/react-tailwind-sync/src/App.tsx +28 -0
  37. package/templates/svelte-basic/AGENTS.md +76 -0
  38. package/templates/svelte-basic/src/App.svelte +27 -31
  39. package/templates/svelte-basic/src/Root.svelte +4 -4
  40. package/templates/svelte-basic/src/modules/todos/useTodos.ts +1 -1
  41. package/templates/svelte-basic/vite.config.ts +1 -1
  42. package/templates/svelte-sync/AGENTS.md +76 -0
  43. package/templates/svelte-sync/src/App.svelte +31 -35
  44. package/templates/svelte-sync/src/Root.svelte +6 -6
  45. package/templates/svelte-sync/src/modules/todos/useTodos.ts +1 -1
  46. package/templates/svelte-tailwind/AGENTS.md +76 -0
  47. package/templates/svelte-tailwind/src/App.svelte +17 -21
  48. package/templates/svelte-tailwind/src/Root.svelte +4 -4
  49. package/templates/svelte-tailwind/src/modules/todos/useTodos.ts +1 -1
  50. package/templates/svelte-tailwind/vite.config.ts +2 -2
  51. package/templates/svelte-tailwind-sync/AGENTS.md +76 -0
  52. package/templates/svelte-tailwind-sync/src/App.svelte +52 -56
  53. package/templates/svelte-tailwind-sync/src/Root.svelte +6 -6
  54. package/templates/svelte-tailwind-sync/src/modules/todos/useTodos.ts +1 -1
  55. package/templates/svelte-tailwind-sync/vite.config.ts +1 -1
  56. package/templates/tauri-react/AGENTS.md +91 -0
  57. package/templates/vue-basic/AGENTS.md +84 -0
  58. package/templates/vue-basic/src/modules/todos/useTodos.ts +1 -1
  59. package/templates/vue-sync/AGENTS.md +84 -0
  60. package/templates/vue-sync/src/main.ts +5 -1
  61. package/templates/vue-sync/src/modules/todos/useTodos.ts +1 -1
  62. package/templates/vue-tailwind/AGENTS.md +84 -0
  63. package/templates/vue-tailwind/src/App.vue +1 -8
  64. package/templates/vue-tailwind/src/modules/todos/useTodos.ts +1 -1
  65. package/templates/vue-tailwind-sync/AGENTS.md +84 -0
  66. package/templates/vue-tailwind-sync/src/modules/todos/useTodos.ts +1 -1
  67. package/dist/chunk-VLTPEATY.js.map +0 -1
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/utils/fs-helpers.ts
4
+ import { access, readFile } from "fs/promises";
5
+ import { dirname, join, resolve } from "path";
6
+ async function directoryExists(path) {
7
+ try {
8
+ await access(path);
9
+ return true;
10
+ } catch {
11
+ return false;
12
+ }
13
+ }
14
+ async function findProjectRoot(startDir) {
15
+ let current = resolve(startDir ?? process.cwd());
16
+ for (; ; ) {
17
+ const pkgPath = join(current, "package.json");
18
+ try {
19
+ const content = await readFile(pkgPath, "utf-8");
20
+ const pkg = JSON.parse(content);
21
+ if (isKoraProject(pkg)) {
22
+ return current;
23
+ }
24
+ } catch {
25
+ }
26
+ const parent = dirname(current);
27
+ if (parent === current) break;
28
+ current = parent;
29
+ }
30
+ return null;
31
+ }
32
+ async function findSchemaFile(projectRoot) {
33
+ const candidates = [
34
+ join(projectRoot, "src", "schema.ts"),
35
+ join(projectRoot, "schema.ts"),
36
+ join(projectRoot, "src", "schema.js"),
37
+ join(projectRoot, "schema.js")
38
+ ];
39
+ for (const candidate of candidates) {
40
+ try {
41
+ await access(candidate);
42
+ return candidate;
43
+ } catch {
44
+ }
45
+ }
46
+ return null;
47
+ }
48
+ async function hasTsxInstalled(projectRoot) {
49
+ try {
50
+ await access(join(projectRoot, "node_modules", "tsx", "package.json"));
51
+ return true;
52
+ } catch {
53
+ return false;
54
+ }
55
+ }
56
+ async function resolveProjectBinaryEntryPoint(projectRoot, packageName, binaryName) {
57
+ const pkgJsonPath = join(projectRoot, "node_modules", packageName, "package.json");
58
+ try {
59
+ const content = await readFile(pkgJsonPath, "utf-8");
60
+ const pkg = JSON.parse(content);
61
+ let binPath;
62
+ if (typeof pkg.bin === "string") {
63
+ binPath = pkg.bin;
64
+ } else if (typeof pkg.bin === "object" && pkg.bin !== null) {
65
+ binPath = pkg.bin[binaryName];
66
+ }
67
+ if (!binPath) return null;
68
+ const fullPath = join(projectRoot, "node_modules", packageName, binPath);
69
+ await access(fullPath);
70
+ return fullPath;
71
+ } catch {
72
+ return null;
73
+ }
74
+ }
75
+ function isKoraProject(pkg) {
76
+ if (typeof pkg !== "object" || pkg === null) return false;
77
+ const record = pkg;
78
+ return hasKoraDep(record.dependencies) || hasKoraDep(record.devDependencies);
79
+ }
80
+ function hasKoraDep(deps) {
81
+ if (typeof deps !== "object" || deps === null) return false;
82
+ return Object.keys(deps).some((key) => key === "kora" || key.startsWith("@korajs/"));
83
+ }
84
+
85
+ export {
86
+ directoryExists,
87
+ findProjectRoot,
88
+ findSchemaFile,
89
+ hasTsxInstalled,
90
+ resolveProjectBinaryEntryPoint
91
+ };
92
+ //# sourceMappingURL=chunk-5NI2FEQL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/fs-helpers.ts"],"sourcesContent":["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"],"mappings":";;;AAAA,SAAS,QAAQ,gBAAgB;AACjC,SAAS,SAAS,MAAM,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,UAAU,KAAK,SAAS,cAAc;AAC5C,QAAI;AACH,YAAM,UAAU,MAAM,SAAS,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,IAClB,KAAK,aAAa,OAAO,WAAW;AAAA,IACpC,KAAK,aAAa,WAAW;AAAA,IAC7B,KAAK,aAAa,OAAO,WAAW;AAAA,IACpC,KAAK,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,OAAO,KAAK,aAAa,gBAAgB,OAAO,cAAc,CAAC;AACrE,WAAO;AAAA,EACR,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AASA,eAAsB,+BACrB,aACA,aACA,YACyB;AACzB,QAAM,cAAc,KAAK,aAAa,gBAAgB,aAAa,cAAc;AACjF,MAAI;AACH,UAAM,UAAU,MAAM,SAAS,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,WAAW,KAAK,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;","names":[]}
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ hasTsxInstalled
4
+ } from "./chunk-5NI2FEQL.js";
5
+
6
+ // src/commands/migrate/schema-loader.ts
7
+ import { spawn } from "child_process";
8
+ import { extname } from "path";
9
+ import { pathToFileURL } from "url";
10
+ async function loadSchemaDefinition(schemaPath, projectRoot) {
11
+ const ext = extname(schemaPath);
12
+ const moduleValue = ext === ".ts" || ext === ".mts" || ext === ".cts" ? await loadTypeScriptModule(schemaPath, projectRoot) : await import(`${pathToFileURL(schemaPath).href}?t=${Date.now()}-${Math.random()}`);
13
+ return extractSchema(moduleValue);
14
+ }
15
+ function extractSchema(value) {
16
+ if (typeof value !== "object" || value === null) {
17
+ throw new Error("Schema module must export an object.");
18
+ }
19
+ const moduleRecord = value;
20
+ const candidate = moduleRecord.default ?? moduleRecord;
21
+ if (!isSchemaDefinition(candidate)) {
22
+ throw new Error("Schema module must export a valid SchemaDefinition as default export.");
23
+ }
24
+ return candidate;
25
+ }
26
+ function isSchemaDefinition(value) {
27
+ if (typeof value !== "object" || value === null) return false;
28
+ const object = value;
29
+ return typeof object.version === "number" && typeof object.collections === "object" && object.collections !== null && typeof object.relations === "object" && object.relations !== null;
30
+ }
31
+ async function loadTypeScriptModule(schemaPath, projectRoot) {
32
+ if (!await hasTsxInstalled(projectRoot)) {
33
+ throw new Error(
34
+ `Schema file is TypeScript (${schemaPath}) but local "tsx" was not found. Install tsx in the project.`
35
+ );
36
+ }
37
+ const script = "const modulePath = process.argv[process.argv.length - 1];import('node:url').then(u => import(u.pathToFileURL(modulePath).href)).then(mod => { const v = mod.default ?? mod; process.stdout.write(JSON.stringify(v)) }).catch(e => { process.stderr.write(String(e)); process.exit(1) })";
38
+ const output = await runCommand(
39
+ process.execPath,
40
+ ["--import", "tsx", "--eval", script, schemaPath],
41
+ projectRoot
42
+ );
43
+ try {
44
+ return JSON.parse(output);
45
+ } catch {
46
+ throw new Error(`Failed to parse schema module output for ${schemaPath}`);
47
+ }
48
+ }
49
+ async function runCommand(command, args, cwd) {
50
+ return await new Promise((resolve, reject) => {
51
+ const child = spawn(command, args, {
52
+ cwd,
53
+ stdio: ["ignore", "pipe", "pipe"],
54
+ env: process.env
55
+ });
56
+ let stdout = "";
57
+ let stderr = "";
58
+ child.stdout?.on("data", (chunk) => {
59
+ stdout += chunk.toString("utf-8");
60
+ });
61
+ child.stderr?.on("data", (chunk) => {
62
+ stderr += chunk.toString("utf-8");
63
+ });
64
+ child.on("error", (error) => {
65
+ reject(error);
66
+ });
67
+ child.on("exit", (code) => {
68
+ if (code === 0) {
69
+ resolve(stdout.trim());
70
+ return;
71
+ }
72
+ reject(
73
+ new Error(`Failed to load TypeScript schema (exit ${code ?? "unknown"}): ${stderr.trim()}`)
74
+ );
75
+ });
76
+ });
77
+ }
78
+
79
+ export {
80
+ loadSchemaDefinition
81
+ };
82
+ //# sourceMappingURL=chunk-6C4BHSRA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/migrate/schema-loader.ts"],"sourcesContent":["import { spawn } from 'node:child_process'\nimport { extname } from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport type { SchemaDefinition } from '@korajs/core'\nimport { hasTsxInstalled } from '../../utils/fs-helpers'\n\n/**\n * Loads a schema definition from a TS/JS module.\n */\nexport async function loadSchemaDefinition(\n\tschemaPath: string,\n\tprojectRoot: string,\n): Promise<SchemaDefinition> {\n\tconst ext = extname(schemaPath)\n\tconst moduleValue =\n\t\text === '.ts' || ext === '.mts' || ext === '.cts'\n\t\t\t? await loadTypeScriptModule(schemaPath, projectRoot)\n\t\t\t: await import(`${pathToFileURL(schemaPath).href}?t=${Date.now()}-${Math.random()}`)\n\n\treturn extractSchema(moduleValue)\n}\n\nfunction extractSchema(value: unknown): SchemaDefinition {\n\tif (typeof value !== 'object' || value === null) {\n\t\tthrow new Error('Schema module must export an object.')\n\t}\n\n\tconst moduleRecord = value as Record<string, unknown>\n\tconst candidate = moduleRecord.default ?? moduleRecord\n\n\tif (!isSchemaDefinition(candidate)) {\n\t\tthrow new Error('Schema module must export a valid SchemaDefinition as default export.')\n\t}\n\n\treturn candidate\n}\n\nfunction isSchemaDefinition(value: unknown): value is SchemaDefinition {\n\tif (typeof value !== 'object' || value === null) return false\n\tconst object = value as Record<string, unknown>\n\treturn (\n\t\ttypeof object.version === 'number' &&\n\t\ttypeof object.collections === 'object' &&\n\t\tobject.collections !== null &&\n\t\ttypeof object.relations === 'object' &&\n\t\tobject.relations !== null\n\t)\n}\n\nasync function loadTypeScriptModule(schemaPath: string, projectRoot: string): Promise<unknown> {\n\tif (!(await hasTsxInstalled(projectRoot))) {\n\t\tthrow new Error(\n\t\t\t`Schema file is TypeScript (${schemaPath}) but local \"tsx\" was not found. Install tsx in the project.`,\n\t\t)\n\t}\n\n\tconst script =\n\t\t'const modulePath = process.argv[process.argv.length - 1];' +\n\t\t\"import('node:url').then(u => import(u.pathToFileURL(modulePath).href))\" +\n\t\t'.then(mod => { const v = mod.default ?? mod; process.stdout.write(JSON.stringify(v)) })' +\n\t\t'.catch(e => { process.stderr.write(String(e)); process.exit(1) })'\n\n\tconst output = await runCommand(\n\t\tprocess.execPath,\n\t\t['--import', 'tsx', '--eval', script, schemaPath],\n\t\tprojectRoot,\n\t)\n\n\ttry {\n\t\treturn JSON.parse(output)\n\t} catch {\n\t\tthrow new Error(`Failed to parse schema module output for ${schemaPath}`)\n\t}\n}\n\nasync function runCommand(command: string, args: string[], cwd: string): Promise<string> {\n\treturn await new Promise<string>((resolve, reject) => {\n\t\tconst child = spawn(command, args, {\n\t\t\tcwd,\n\t\t\tstdio: ['ignore', 'pipe', 'pipe'],\n\t\t\tenv: process.env,\n\t\t})\n\n\t\tlet stdout = ''\n\t\tlet stderr = ''\n\n\t\tchild.stdout?.on('data', (chunk: Buffer) => {\n\t\t\tstdout += chunk.toString('utf-8')\n\t\t})\n\n\t\tchild.stderr?.on('data', (chunk: Buffer) => {\n\t\t\tstderr += chunk.toString('utf-8')\n\t\t})\n\n\t\tchild.on('error', (error) => {\n\t\t\treject(error)\n\t\t})\n\n\t\tchild.on('exit', (code) => {\n\t\t\tif (code === 0) {\n\t\t\t\tresolve(stdout.trim())\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\treject(\n\t\t\t\tnew Error(`Failed to load TypeScript schema (exit ${code ?? 'unknown'}): ${stderr.trim()}`),\n\t\t\t)\n\t\t})\n\t})\n}\n"],"mappings":";;;;;;AAAA,SAAS,aAAa;AACtB,SAAS,eAAe;AACxB,SAAS,qBAAqB;AAO9B,eAAsB,qBACrB,YACA,aAC4B;AAC5B,QAAM,MAAM,QAAQ,UAAU;AAC9B,QAAM,cACL,QAAQ,SAAS,QAAQ,UAAU,QAAQ,SACxC,MAAM,qBAAqB,YAAY,WAAW,IAClD,MAAM,OAAO,GAAG,cAAc,UAAU,EAAE,IAAI,MAAM,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC;AAEnF,SAAO,cAAc,WAAW;AACjC;AAEA,SAAS,cAAc,OAAkC;AACxD,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAChD,UAAM,IAAI,MAAM,sCAAsC;AAAA,EACvD;AAEA,QAAM,eAAe;AACrB,QAAM,YAAY,aAAa,WAAW;AAE1C,MAAI,CAAC,mBAAmB,SAAS,GAAG;AACnC,UAAM,IAAI,MAAM,uEAAuE;AAAA,EACxF;AAEA,SAAO;AACR;AAEA,SAAS,mBAAmB,OAA2C;AACtE,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,SAAS;AACf,SACC,OAAO,OAAO,YAAY,YAC1B,OAAO,OAAO,gBAAgB,YAC9B,OAAO,gBAAgB,QACvB,OAAO,OAAO,cAAc,YAC5B,OAAO,cAAc;AAEvB;AAEA,eAAe,qBAAqB,YAAoB,aAAuC;AAC9F,MAAI,CAAE,MAAM,gBAAgB,WAAW,GAAI;AAC1C,UAAM,IAAI;AAAA,MACT,8BAA8B,UAAU;AAAA,IACzC;AAAA,EACD;AAEA,QAAM,SACL;AAKD,QAAM,SAAS,MAAM;AAAA,IACpB,QAAQ;AAAA,IACR,CAAC,YAAY,OAAO,UAAU,QAAQ,UAAU;AAAA,IAChD;AAAA,EACD;AAEA,MAAI;AACH,WAAO,KAAK,MAAM,MAAM;AAAA,EACzB,QAAQ;AACP,UAAM,IAAI,MAAM,4CAA4C,UAAU,EAAE;AAAA,EACzE;AACD;AAEA,eAAe,WAAW,SAAiB,MAAgB,KAA8B;AACxF,SAAO,MAAM,IAAI,QAAgB,CAAC,SAAS,WAAW;AACrD,UAAM,QAAQ,MAAM,SAAS,MAAM;AAAA,MAClC;AAAA,MACA,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,MAChC,KAAK,QAAQ;AAAA,IACd,CAAC;AAED,QAAI,SAAS;AACb,QAAI,SAAS;AAEb,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AAC3C,gBAAU,MAAM,SAAS,OAAO;AAAA,IACjC,CAAC;AAED,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AAC3C,gBAAU,MAAM,SAAS,OAAO;AAAA,IACjC,CAAC;AAED,UAAM,GAAG,SAAS,CAAC,UAAU;AAC5B,aAAO,KAAK;AAAA,IACb,CAAC;AAED,UAAM,GAAG,QAAQ,CAAC,SAAS;AAC1B,UAAI,SAAS,GAAG;AACf,gBAAQ,OAAO,KAAK,CAAC;AACrB;AAAA,MACD;AAEA;AAAA,QACC,IAAI,MAAM,0CAA0C,QAAQ,SAAS,MAAM,OAAO,KAAK,CAAC,EAAE;AAAA,MAC3F;AAAA,IACD,CAAC;AAAA,EACF,CAAC;AACF;","names":[]}
@@ -110,18 +110,18 @@ import {
110
110
  // src/utils/prompt.ts
111
111
  import { createInterface } from "readline";
112
112
  function promptText(message, defaultValue, options) {
113
- return new Promise((resolve2) => {
113
+ return new Promise((resolve) => {
114
114
  const rl = createReadline(options);
115
115
  const suffix = defaultValue !== void 0 ? ` (${defaultValue})` : "";
116
116
  rl.question(` ? ${message}${suffix}: `, (answer) => {
117
117
  rl.close();
118
118
  const trimmed = answer.trim();
119
- resolve2(trimmed || defaultValue || "");
119
+ resolve(trimmed || defaultValue || "");
120
120
  });
121
121
  });
122
122
  }
123
123
  function promptSelect(message, choices, options) {
124
- return new Promise((resolve2) => {
124
+ return new Promise((resolve) => {
125
125
  const rl = createReadline(options);
126
126
  const out = options?.output ?? process.stdout;
127
127
  out.write(` ? ${message}
@@ -139,7 +139,7 @@ function promptSelect(message, choices, options) {
139
139
  const selected = choices[index];
140
140
  if (selected) {
141
141
  rl.close();
142
- resolve2(selected.value);
142
+ resolve(selected.value);
143
143
  } else {
144
144
  out.write(` Please enter a number between 1 and ${choices.length}
145
145
  `);
@@ -151,7 +151,7 @@ function promptSelect(message, choices, options) {
151
151
  });
152
152
  }
153
153
  function promptConfirm(message, defaultValue = false, options) {
154
- return new Promise((resolve2) => {
154
+ return new Promise((resolve) => {
155
155
  const rl = createReadline(options);
156
156
  const suffix = defaultValue ? "Y/n" : "y/N";
157
157
  const ask = () => {
@@ -159,17 +159,17 @@ function promptConfirm(message, defaultValue = false, options) {
159
159
  const normalized = answer.trim().toLowerCase();
160
160
  if (normalized.length === 0) {
161
161
  rl.close();
162
- resolve2(defaultValue);
162
+ resolve(defaultValue);
163
163
  return;
164
164
  }
165
165
  if (normalized === "y" || normalized === "yes") {
166
166
  rl.close();
167
- resolve2(true);
167
+ resolve(true);
168
168
  return;
169
169
  }
170
170
  if (normalized === "n" || normalized === "no") {
171
171
  rl.close();
172
- resolve2(false);
172
+ resolve(false);
173
173
  return;
174
174
  }
175
175
  ;
@@ -748,88 +748,6 @@ function createLogger(options) {
748
748
  };
749
749
  }
750
750
 
751
- // src/utils/fs-helpers.ts
752
- import { access, readFile as readFile2 } from "fs/promises";
753
- import { dirname, join as join2, resolve } from "path";
754
- async function directoryExists(path) {
755
- try {
756
- await access(path);
757
- return true;
758
- } catch {
759
- return false;
760
- }
761
- }
762
- async function findProjectRoot(startDir) {
763
- let current = resolve(startDir ?? process.cwd());
764
- for (; ; ) {
765
- const pkgPath = join2(current, "package.json");
766
- try {
767
- const content = await readFile2(pkgPath, "utf-8");
768
- const pkg = JSON.parse(content);
769
- if (isKoraProject(pkg)) {
770
- return current;
771
- }
772
- } catch {
773
- }
774
- const parent = dirname(current);
775
- if (parent === current) break;
776
- current = parent;
777
- }
778
- return null;
779
- }
780
- async function findSchemaFile(projectRoot) {
781
- const candidates = [
782
- join2(projectRoot, "src", "schema.ts"),
783
- join2(projectRoot, "schema.ts"),
784
- join2(projectRoot, "src", "schema.js"),
785
- join2(projectRoot, "schema.js")
786
- ];
787
- for (const candidate of candidates) {
788
- try {
789
- await access(candidate);
790
- return candidate;
791
- } catch {
792
- }
793
- }
794
- return null;
795
- }
796
- async function hasTsxInstalled(projectRoot) {
797
- try {
798
- await access(join2(projectRoot, "node_modules", "tsx", "package.json"));
799
- return true;
800
- } catch {
801
- return false;
802
- }
803
- }
804
- async function resolveProjectBinaryEntryPoint(projectRoot, packageName, binaryName) {
805
- const pkgJsonPath = join2(projectRoot, "node_modules", packageName, "package.json");
806
- try {
807
- const content = await readFile2(pkgJsonPath, "utf-8");
808
- const pkg = JSON.parse(content);
809
- let binPath;
810
- if (typeof pkg.bin === "string") {
811
- binPath = pkg.bin;
812
- } else if (typeof pkg.bin === "object" && pkg.bin !== null) {
813
- binPath = pkg.bin[binaryName];
814
- }
815
- if (!binPath) return null;
816
- const fullPath = join2(projectRoot, "node_modules", packageName, binPath);
817
- await access(fullPath);
818
- return fullPath;
819
- } catch {
820
- return null;
821
- }
822
- }
823
- function isKoraProject(pkg) {
824
- if (typeof pkg !== "object" || pkg === null) return false;
825
- const record = pkg;
826
- return hasKoraDep(record.dependencies) || hasKoraDep(record.devDependencies);
827
- }
828
- function hasKoraDep(deps) {
829
- if (typeof deps !== "object" || deps === null) return false;
830
- return Object.keys(deps).some((key) => key === "kora" || key.startsWith("@korajs/"));
831
- }
832
-
833
751
  export {
834
752
  createLogger,
835
753
  CliError,
@@ -837,11 +755,6 @@ export {
837
755
  SchemaNotFoundError,
838
756
  InvalidProjectError,
839
757
  DevServerError,
840
- directoryExists,
841
- findProjectRoot,
842
- findSchemaFile,
843
- hasTsxInstalled,
844
- resolveProjectBinaryEntryPoint,
845
758
  PreferenceStore,
846
759
  getCreatePreferencesOrDefault,
847
760
  getDefaultCreatePreferences,
@@ -865,4 +778,4 @@ export {
865
778
  validateProjectName,
866
779
  applySyncProviderPreset
867
780
  };
868
- //# sourceMappingURL=chunk-VLTPEATY.js.map
781
+ //# sourceMappingURL=chunk-B5YS4STN.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/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 {\n\tAuthOption,\n\tDatabaseOption,\n\tDatabaseProviderOption,\n\tFrameworkOption,\n\tPlatformOption,\n} 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 =\n\t\ttypeof 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\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'vue-sync',\n\t'vue-basic',\n\t'vue-tailwind-sync',\n\t'vue-tailwind',\n\t'svelte-sync',\n\t'svelte-basic',\n\t'svelte-tailwind-sync',\n\t'svelte-tailwind',\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: 'vue-sync',\n\t\tlabel: 'Vue 3 + CSS (with sync)',\n\t\tdescription: 'Vue composables with sync server included',\n\t},\n\t{\n\t\tname: 'vue-basic',\n\t\tlabel: 'Vue 3 + CSS (local-only)',\n\t\tdescription: 'Vue composables — no sync server',\n\t},\n\t{\n\t\tname: 'vue-tailwind-sync',\n\t\tlabel: 'Vue 3 + Tailwind (with sync)',\n\t\tdescription: 'Polished Vue app with Tailwind CSS and sync server',\n\t},\n\t{\n\t\tname: 'vue-tailwind',\n\t\tlabel: 'Vue 3 + Tailwind (local-only)',\n\t\tdescription: 'Polished Vue app with Tailwind CSS — no sync server',\n\t},\n\t{\n\t\tname: 'svelte-sync',\n\t\tlabel: 'Svelte 5 + CSS (with sync)',\n\t\tdescription: 'Svelte stores with sync server included',\n\t},\n\t{\n\t\tname: 'svelte-basic',\n\t\tlabel: 'Svelte 5 + CSS (local-only)',\n\t\tdescription: 'Svelte stores — no sync server',\n\t},\n\t{\n\t\tname: 'svelte-tailwind-sync',\n\t\tlabel: 'Svelte 5 + Tailwind (with sync)',\n\t\tdescription: 'Polished Svelte app with Tailwind CSS and sync server',\n\t},\n\t{\n\t\tname: 'svelte-tailwind',\n\t\tlabel: 'Svelte 5 + Tailwind (local-only)',\n\t\tdescription: 'Polished Svelte app with Tailwind CSS — 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\tframework: FrameworkOption\n\ttailwind: boolean\n\tsync: boolean\n\tdb: DatabaseOption\n}\n\n/**\n * Converts high-level scaffold selections into a concrete template name.\n */\nexport function determineTemplateFromSelections(input: TemplateSelectionInput): TemplateName {\n\tif (input.platform === 'desktop-tauri') return 'tauri-react'\n\n\tconst shouldSync = input.sync && input.db !== 'none'\n\n\tif (input.framework === 'vue') {\n\t\tif (input.tailwind && shouldSync) return 'vue-tailwind-sync'\n\t\tif (input.tailwind && !shouldSync) return 'vue-tailwind'\n\t\treturn shouldSync ? 'vue-sync' : 'vue-basic'\n\t}\n\n\tif (input.framework === 'svelte') {\n\t\tif (input.tailwind && shouldSync) return 'svelte-tailwind-sync'\n\t\tif (input.tailwind && !shouldSync) return 'svelte-tailwind'\n\t\treturn shouldSync ? 'svelte-sync' : 'svelte-basic'\n\t}\n\n\tif (input.framework === 'solid') {\n\t\tthrow new Error('Solid templates are not available yet. Use react, vue, or svelte.')\n\t}\n\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\nexport function isSupportedWebFramework(framework: FrameworkOption): boolean {\n\treturn framework === 'react' || framework === 'vue' || framework === 'svelte'\n}\n","import {\n\ttype CreatePreferences,\n\ttype PreferenceStore,\n\tgetCreatePreferencesOrDefault,\n\tgetDefaultCreatePreferences,\n} from '../../prompts/preferences'\nimport type { PromptClient } from '../../prompts/prompt-client'\nimport {\n\ttype AuthOption,\n\ttype DatabaseOption,\n\ttype DatabaseProviderOption,\n\ttype FrameworkOption,\n\ttype PlatformOption,\n\tdetermineTemplateFromSelections,\n\tisAuthValue,\n\tisDatabaseProviderValue,\n\tisDatabaseValue,\n\tisFrameworkValue,\n\tisPlatformValue,\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 currently uses React and native SQLite on the client.\n\t\t// The sync server remains configurable so the same desktop scaffold can\n\t\t// run local-only, LAN sync, or cloud sync without switching templates.\n\t\teffective.framework = 'react'\n\t\teffective.tailwind = false\n\t\teffective.auth = 'none'\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(\n\t\t\t\t\t`Invalid --db value \"${flags.db}\". Expected one of: none, sqlite, postgres.`,\n\t\t\t\t)\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('Sync server database:', [\n\t\t\t\t{ label: 'SQLite (zero-config; local, LAN, small teams)', 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 === 'none') {\n\t\t\teffective.sync = false\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} 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 3', value: 'vue' },\n\t\t\t\t{ label: 'Svelte 5', value: 'svelte' },\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(\n\t\t\t\t\t`Invalid --db value \"${flags.db}\". Expected one of: none, sqlite, postgres.`,\n\t\t\t\t)\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\tframework: effective.framework,\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 * The sync server template is environment-driven: SQLite is used when\n * DATABASE_URL is absent, and PostgreSQL is used when DATABASE_URL is present.\n * Provider presets only add provider-specific guidance.\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 envPath = join(options.targetDir, '.env.example')\n\tconst readmePath = join(options.targetDir, 'README.md')\n\n\tconst existingReadme = await readFile(readmePath, 'utf-8')\n\tconst existingEnv = await readFile(envPath, 'utf-8')\n\tconst trimmedReadme = existingReadme.trimEnd()\n\tconst trimmedEnv = existingEnv.trimEnd()\n\tconst envSuffix = [\n\t\t'',\n\t\t`# PostgreSQL provider preset: ${providerName}`,\n\t\t`# Example: ${providerConnectionString}`,\n\t].join('\\n')\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 keeps one sync server entrypoint. When `DATABASE_URL` is set, `server.ts` uses PostgreSQL. When it is empty, the same server uses SQLite at `KORA_SERVER_DB`.',\n\t\t'',\n\t\t'The generated server uses `createPostgresServerStore` automatically when `DATABASE_URL` is present.',\n\t\t'',\n\t].join('\\n')\n\tconst readmeTemplate = `${trimmedReadme}${readmeSuffix}`\n\n\tawait writeFile(envPath, `${trimmedEnv}${envSuffix}\\n`, 'utf-8')\n\tawait writeFile(readmePath, readmeTemplate, 'utf-8')\n}\n\nfunction isSyncTemplate(template: TemplateName): boolean {\n\treturn (\n\t\ttemplate === 'react-sync' ||\n\t\ttemplate === 'react-tailwind-sync' ||\n\t\ttemplate === 'vue-sync' ||\n\t\ttemplate === 'vue-tailwind-sync' ||\n\t\ttemplate === 'svelte-sync' ||\n\t\ttemplate === 'svelte-tailwind-sync' ||\n\t\ttemplate === 'tauri-react'\n\t)\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","/** 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":"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","names":[]}
@@ -8,13 +8,15 @@ import {
8
8
  applySyncProviderPreset,
9
9
  createLogger,
10
10
  createPromptClient,
11
- directoryExists,
12
11
  isSupportedWebFramework,
13
12
  resolveCreatePreferencesFlow,
14
13
  saveResolvedPreferences,
15
14
  shouldSavePreferences,
16
15
  validateProjectName
17
- } from "./chunk-VLTPEATY.js";
16
+ } from "./chunk-B5YS4STN.js";
17
+ import {
18
+ directoryExists
19
+ } from "./chunk-5NI2FEQL.js";
18
20
 
19
21
  // src/commands/create/create-command.ts
20
22
  import { execSync as execSync2 } from "child_process";
@@ -273,7 +275,9 @@ function createCompatibilityLayerPlan(templateName) {
273
275
  case "vue-tailwind-sync":
274
276
  return {
275
277
  compatibilityTarget: templateName,
276
- layers: [{ category: "base", name: "vue-tailwind-sync", sourceTemplate: "vue-tailwind-sync" }]
278
+ layers: [
279
+ { category: "base", name: "vue-tailwind-sync", sourceTemplate: "vue-tailwind-sync" }
280
+ ]
277
281
  };
278
282
  case "vue-tailwind":
279
283
  return {
@@ -284,7 +288,11 @@ function createCompatibilityLayerPlan(templateName) {
284
288
  return {
285
289
  compatibilityTarget: templateName,
286
290
  layers: [
287
- { category: "base", name: "svelte-tailwind-sync", sourceTemplate: "svelte-tailwind-sync" }
291
+ {
292
+ category: "base",
293
+ name: "svelte-tailwind-sync",
294
+ sourceTemplate: "svelte-tailwind-sync"
295
+ }
288
296
  ]
289
297
  };
290
298
  case "svelte-tailwind":
@@ -669,4 +677,4 @@ function resolveKoraVersion() {
669
677
  export {
670
678
  createCommand
671
679
  };
672
- //# sourceMappingURL=chunk-EEZNRI5W.js.map
680
+ //# sourceMappingURL=chunk-BWTKRKNJ.js.map